//https://randomnerdtutorials.com/esp32-dc-motor-l298n-motor-driver-control-speed-direction/
#include <Arduino.h>
/************************************************************************
SD CARD
************************************************************************
INCLUDES
************************************************************************/
#include <SD.h>
/************************************************************************
PINS
************************************************************************/
#define SD_CS_PIN 10
// MOSI ( 11 ) -> DI | MOSI | DATA-IN | GRUEN
// MISO ( 13 ) -> DO | MISO | DATA-OUT | GELB
// SCK ( 12 ) -> SCK | SCL | CLK | BLAU
// SS ( 10 ) -> CS | ChipSelect | LILA
/************************************************************************/
/************************************************************************
OLED DISPLAY
************************************************************************
INCLUDES
************************************************************************/
#include <U8g2lib.h>
/************************************************************************
PINS
************************************************************************
SPI Interface
************************************************************************/
//#define OLED_CLK 12 // D0 | SCK | SCL | CLK | BLAU
//#define OLED_MOSI 11 // D1 | SDA | MOSI | GRUEN
//#define OLED_RESET 46 // RES | RST | RESET | GRAU
//#define OLED_DC 3 // DC | A0 | WEISS
//#define OLED_CS 14 // CS | ChipSelect | LILA
/************************************************************************
I2C Interface
************************************************************************/
// SDA ( 8 ) -> SDA | GRUEN
// SCL ( 9 ) -> SCL | BLAU
/************************************************************************
constructor:
************************************************************************/
// For WOKWI
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
//U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
/************************************************************************
SOME VARIABLES:
************************************************************************/
int SCREEN_WIDTH;
int SCREEN_HEIGHT;
int USABLE_SCREEN_WIDTH;
/************************************************************************
CUSTOM FONT(s):
************************************************************************/
const uint8_t u8g2_font_tpss_tn[2005] U8G2_FONT_SECTION("u8g2_font_tpss_tn") =
"\263\0\3\2\4\4\2\5\5\13\21\377\374\11\374\11\0\1X\2\257\7\270 \5\0B\12!\7\221\303"
"\211\213\0\42\7#\337\212D\11#\13U\303\233\312\240T\6\245\2$\20\225\303\233\245\242d[\22%"
"J\242T\26\0%\15\225\303\213L\12\263\260\26FZ\0&\21\227\303\234\255\224e[)\213\262(K"
"\222%\1'\6!\337\11\1(\14\225\303;)\13\263\64LS\1)\14\225\303\13\265\230fa\26i"
"\0*\13u\307\253Je\313\226\246\10+\12U\307\253\60\32\244\60\2,\6\42\77\32\5-\6\25\317"
"\213A.\6\21\303\211\0/\14\225\303\313,\314\302Z\230\205\0\60\12\225B\233%\363[\262\0\61\13"
"\225B\253LJ\302\236\6\1\62\13\225B\233%\323\302\254\343 \63\15\225B\233%\13#\65\14\265d"
"\1\64\11\225BKM\33\306\36\65\14\225B\213c\70\210E-Y\0\66\15\225B\233%\23\207$s"
"K\26\0\67\12\225B\213A\314\32\273\1\70\15\225B\233%\323\222%sK\26\0\71\15\225B\233%"
"\263%C\30j\311\2:\6A\303\211(;\7R\77\232T\1<\10\225\303\313\254k\7=\10\65\313"
"\213A\35\4>\11\225\303\213\264[G\0\77\15\225\303\233%\13\263b\16\205\21\0@\25\211\303\235a"
"\212\223HJJISRR\242\34H\206!\1A\13\225B\233%\323\206!\363\26B\15\225B\213!"
"\311\264A\311\334\6\5C\13\225B\233%\23{K\26\0D\13\225B\213!\311\374\66(\0E\13\225"
"B\213c\70$a\343 F\13\225B\213c\70$aG\0G\15\225B\233%\23\223!sK\26\0"
"H\13\225B\213\314\66\14\231\267\0I\6\221B\211\7J\11\225B\313>j\311\2K\16\225B\213\314"
"\224\224\264$\252dZ\0L\11\225B\213\260\37\7\1M\14\227B\214t[*R\244z\15N\13\225"
"B\213lR\22i\363\26O\12\225B\233%\363[\262\0P\14\225B\213!\311\264A\11;\2Q\15"
"\225B\233%\363\222(\211RY\0R\14\225B\213!\311\264A\311\274\5S\14\225B\233%S\327P"
"\323\222\5T\11\225B\213A\12\373\11U\11\225B\213\314\337\222\5V\17\225B\213\314\226\224\222(\211"
"\222,\214\0W\21\227B\214\324\232\64%\245\244\226\204I\230D\0X\15\225B\213LKja\226\324"
"l\1Y\13\225B\213LKjaO\0Z\13\225B\213A\254u\14\7\1[\11\223\303\212!\352\323"
"\0\134\12u\303\213\64L\213i\0]\11\223\303\212\251OC\0^\6#\353\232\6_\6\26C\214\3"
"`\6\42k\32\5a\12eB\233%sK\206\0b\14\225B\213\260\70$\231[\262\0c\12eB"
"\233%\23k\311\2d\13\225B\313\226AsK\206\0e\14eB\233%\33\206\60K\26\0f\13\225"
"B+\251\222ma\67\0g\15\245\62\233%sK\206\60\324\222\5h\12\225B\213\260\305\244\271\5i"
"\7\221B\11e\30j\12\322\262\231Z\322/\12\0k\15\225B\213\260))iIT\311\2l\6\221"
"B\211\7m\16gB\214D\31\22S$ER$\25n\11eB\213\304\244\271\5o\12eB\233%"
"sK\26\0p\13\245\62\233%s\33\224\260\21q\22\246\262\233!\311\222,\311\222,\32\322pL\23"
"\0r\12d\302\212d\210\262\66\0s\12eB\233%]\265d\1t\13\224\302\232\254\64$Y'\0"
"u\11eB\213\314[\262\0v\14eB\213LKJI\26F\0w\16gB\214TM\232\222Z\22"
"&\21\0x\13eB\213,\251\205YR\13y\15\245\62\213\314[\62\204\241\226,\0z\11eB\233"
"A\353\66\10{\14\226CL-L\63\71\215c\1|\6\221\303\211\7}\14\226C\14\271\32ki\230"
"\211\0~\7%j\213E\31\241\7\221B\11e\30\242\15u\303\253l\251(QR\331\42\0\243\14\225"
"\303\213\60\34\222\260M\33\6\244\13U\307\213,\231\222h\311\2\245\17\225\303\213LKja\64H\321"
" E\0\246\6\221\303\211m\247\21\246C\234!\211\207$L\206\70M\305dH\0\250\6\25\317\213,"
"\251\17w\303\234AI\225E\311\224EM\6\5\252\17\206C\234)K\262$K\262h\211\207\1\253\7"
"\65\313\233Hj\254\7%\313\213A\14\255\5\0B\14\256\17w\303\234AI\225E\311\224LM\6\5"
"\257\6\25Z\213A\260\7\63\313\232.\0\261\14u\303\253\60\32\244\60\7\6\1\265\5\0B\14\267\5"
"\0B\14\273\11\65\313\213\250$%\0\300\16\305B\233\64G\226L\33\206\314[\0\301\15\305B\273:"
"\262d\332\60d\336\2\302\16\305B\253,\311\201%\323\206!\363\26\303\16\305B\213E\231\227L\33\206"
"\314[\0\304\15\265B\233:\260d\332\60d\336\2\305\17\325B\253,\311rd\311\264a\310\274\5\306"
"\23\231B\235\341\26f\341\60(Y\230\205Y\230\205\331 \307\14\225:\233%\23\333\222-\223\0\310\16"
"\305B\233\64\7\216\341\220\204\215\203\0\311\15\305B\273:p\14\207$l\34\4\312\16\305B\253,\211"
"\207\61\34\222\260q\20\313\15\265B\233\362\60\206C\22\66\16\2\314\11\302A\211(K\372\3\315\11\302"
"B\31-\351/\0\316\11\303A\231\306\250\277\0\317\12\263A\211$\214\372\13\0\320\15\225B\213!\311"
"\264!\321\334\6\5\321\16\305B\213EY\63\333\244$\322f\13\322\14\305B\233\64G\226\314o\311\2"
"\323\14\305B\273:\262d~K\26\0\324\15\305B\253,\311\201%\363[\262\0\325\14\305B\213E\231"
"\227\314o\311\2\326\14\265B\233:\260d~K\26\0\327\7\63J\213\244\3\330\22\227B\254\245\26E"
"RRJJII\252%\311\4\331\14\305B\233\64\7\62\177K\26\0\332\13\305B\273:\220\371[\262"
"\0\333\14\305B\253,\211\63\177K\26\0\334\12\265B\233r\346o\311\2\335\14\305B\273:\220iI"
"-\354\11\336\15\225B\213\60\34\222lP\302F\0\337\16\265:\213!\311\24%sQ\302F\0\340\14"
"\225B\233\64G\226\314-\31\2\341\13\225B\273:\262dn\311\20\342\15\225B\253,\311\201%sK"
"\206\0\343\14\225B\213E\231\227\314-\31\2\344\13\205B\233:\260dn\311\20\345\15\245B\253,\311"
"rd\311\334\222!\346\16iB\235K\226i\303\26f\225\13\0\347\13\205:\233%\23k\311V\3\350"
"\14eB\233%\33\206\60K\26\0\351\14eB\233%\33\206\60K\26\0\352\14eB\233%\33\206\60"
"K\26\0\353\14eB\233%\33\206\60K\26\0\354\10\242\302\211(Mz\355\10\242\302\31\65\351\5\356"
"\11\243B\232v \352\5\357\12\223B\212$\7\242^\0\360\14\225B\313hL\6\315-\31\2\361\13"
"\225B\213EY\23\223\346\26\362\14\225B\233\64G\226\314-Y\0\363\13\225B\273:\262dn\311\2"
"\364\15\225B\253,\311\201%sK\26\0\365\14\225B\213E\231\227\314-Y\0\366\13\205B\233:\260"
"dn\311\2\367\12UF\253\34\30t \2\370\14eB\233%Z\22%\231\222\5\371\13\225B\233\64"
"\7\62o\311\2\372\13\225B\273:\220yK\26\0\373\13\225B\253,\211\63o\311\2\374\12\205B\233"
"r\346-Y\0\375\16\325\62\273:\220yK\206\60\324\222\5\376\14e\302\212pH\262A\11C\0\377"
"\16\305\62\233r\346-\31\302PK\26\0\0\0\0\4\377\377\0";
/************************************************************************
USED FONTS:
************************************************************************/
/*
5px Height:
Normal: u8g2_font_4x6_tf
6px Height:
Normal: u8g2_font_5x8_tf
7px Height:
Normal: u8g2_font_6x10_tf
9px Height:
Normal: u8g2_font_6x13_tf
Bold: u8g2_font_6x13B_tf
Alt: u8g2_font_tpss_tn
10px Height:
Normal: u8g2_font_7x14_tf
Bold: u8g2_font_7x14B_tf
*/
/************************************************************************
Bitmaps
************************************************************************/
/************************************************************************/
/************************************************************************
LOAD CELL
************************************************************************
INCLUDES
************************************************************************/
#include <HX711_ADC.h>
#if defined(ESP8266)|| defined(ESP32) || defined(AVR)
#include <EEPROM.h>
#endif
/************************************************************************
PINS
************************************************************************/
const int HX711_dout = 5; // HX711_DT
const int HX711_sck = 4; // HX711_SCK
/************************************************************************
HX711 constructor:
************************************************************************/
HX711_ADC LoadCell(HX711_dout, HX711_sck);
/************************************************************************
SOME VARIABLES:
************************************************************************/
const int calVal_eepromAdress = 100;
unsigned long t = 0;
/************************************************************************
ROTARY ENCODER
************************************************************************
INCLUDES
************************************************************************/
#include <AiEsp32RotaryEncoder.h>
/************************************************************************
PINS:
************************************************************************/
#define ENCODER_DT 17 // -> ENCODER_DT
#define ENCODER_CLK 16 // -> ENCODER_CLK
#define ENCODER_SW 18 // -> ENCODER_SW | ENCODER_BTN
#define ROTARY_ENCODER_VCC_PIN -1 // 27 put -1 of Rotary encoder Vcc is connected directly to 3,3V; else you can use declared output pin for powering rotary encoder
/************************************************************************
SOME VARIABLES:
************************************************************************/
//depending on your encoder - try 1,2 or 4 to get expected behaviour
//#define ROTARY_ENCODER_STEPS 1
//#define ROTARY_ENCODER_STEPS 2
#define ROTARY_ENCODER_STEPS 4
/************************************************************************/
unsigned long shortPressAfterMiliseconds = 50; //how long short press shoud be. Do not set too low to avoid bouncing (false press events).
unsigned long longPressAfterMiliseconds = 1000; //how long čong press shoud be.
unsigned long LastEncoderPosChange = 0;
bool circleValues = false;
uint8_t rotaryEncoderMinValue = 0;
uint16_t rotaryEncoderMaxValue = 5000;
/************************************************************************
AiEsp32RotaryEncoder constructor:
************************************************************************/
AiEsp32RotaryEncoder rotaryEncoderAi = AiEsp32RotaryEncoder(ENCODER_DT, ENCODER_CLK, ENCODER_SW, ROTARY_ENCODER_VCC_PIN, ROTARY_ENCODER_STEPS);
/************************************************************************
STRUCT:
************************************************************************/
typedef struct {
bool ButtonPressed = false;
bool ButtonPressedLong = false;
uint32_t LastButtonChange = 0; // last time state of button changed (for debouncing)
} ButtonState_T;
ButtonState_T rotaryButton;
/************************************************************************/
typedef struct {
uint16_t Pos = 1; // current value selected with rotary encoder (updated by interrupt routine
uint16_t LastPos = Pos; // Last Menu Position
uint16_t PosLocked = Pos;
uint8_t MainMenuPos = Pos; // Main Menu Position
bool locked = false;
} rotaryEncoderPos_T;
rotaryEncoderPos_T rotaryEncoderPos;
/************************************************************************
MENU THINGS
************************************************************************/
String menuItems[99];
/*
type Max. value
uint8_t 255
uint16_t 65535
uint32_t 4294967295
uint64_t 2^64 - 1
*/
uint8_t minPos = 1;
uint16_t maxPos = 10;
uint8_t menuPos = 0;
uint8_t currMenu = 0;
uint8_t lastMenu = 0;
uint32_t curr_millis;
uint32_t delta_millis;
uint32_t last_LED_millis;
uint32_t last_CELL_millis;
uint16_t loop_delay = 50;
/************************************************************************
LED
************************************************************************
INCLUDES
************************************************************************/
#include <Adafruit_NeoPixel.h>
//#include <FastLED.h>
/************************************************************************
PINS
************************************************************************/
// https://deepbluembedded.com/esp32-timers-timer-interrupt-tutorial-arduino-ide/
// https://blog.wokwi.com/5-ways-to-blink-an-led-with-arduino/
#define PIN_LED 1
#define PIN_WS2812B 48
#define NUM_PIXELS 24 // The number of LEDs (pixels) on WS2812B LED strip
//CRGB leds[NUM_PIXELS];
/************************************************************************
constructor:
************************************************************************/
Adafruit_NeoPixel ws2812b(NUM_PIXELS, PIN_WS2812B, NEO_GRB + NEO_KHZ800);
/************************************************************************
SOME VARIABLES:
************************************************************************/
bool ledState = false;
/************************************************************************
PUMP SETUP
************************************************************************/
const uint8_t NumPumps = 8;
const uint8_t PumpPIN[NumPumps] = {2, 42, 41, 40, 39, 38, 37, 36};
/* Setting PWM Properties */
const int PWMFreq = 25000; /* 25 KHz */
const int PWMResolution = 8;
const int MAX_DUTY_CYCLE = (int)(pow(2, PWMResolution) - 1);
/************************************************************************
Ingredients
************************************************************************
STRUCT:
************************************************************************/
typedef struct {
uint8_t PumpID;
String IngredientName;
bool alcoholic;
} StructIngredients_T;
/************************************************************************/
StructIngredients_T DefaultIngredient[] =
{
// PumpID, IngredientName, alcoholic
/* 1 */ { 1, "Orangensaft", false},
/* 2 */ { 2, "Grenadine", false},
/* 3 */ { 3, "Tequilla", true },
/* 4 */ { 4, "Weisser Rum", true },
};
StructIngredients_T Ingredient[99];
/************************************************************************
SOME VARIABLES:
************************************************************************/
const int NumDefaultIngredients = (sizeof(DefaultIngredient) / sizeof(StructIngredients_T));
int NumIngredients;
/************************************************************************
Cocktails
************************************************************************
STRUCT:
************************************************************************/
typedef struct {
String CocktailName;
String IngredientName[NumPumps];
uint8_t IngredientAmount[NumPumps];
bool available;
} StructCocktails_T;
/************************************************************************/
StructCocktails_T DefaultCocktail[] =
{
{
"Tequilla Sunrise",
{"Tequilla", "Orangensaft", "Grenadine"},
{ 40, 150, 20}
},
{
"Beispiel 2",
{"Weisser Rum", "Orangensaft", "Grenadine"},
{ 15, 20, 20}
},
{
"Tequilla Sunset",
{"Tequilla", "Orangensaft", "Grenadine"},
{ 40, 150, 20}
}
};
StructCocktails_T Cocktail[99];
/************************************************************************
SOME VARIABLES:
************************************************************************/
const int NumDefaultCocktails = (sizeof(DefaultCocktail) / sizeof(StructCocktails_T));
int NumCocktails;
/************************************************************************/
int NumCocktailsAvailable = 0;
int NumCocktailsMenu = 0;
String tmptxt;
/************************************************************************/
/************************************************************************/
/************************************************************************/
bool SERIAL_CONNECTED = false;
/************************************************************************
START - FUNCTIONS
************************************************************************/
/************************************************************************
BLINK LED
************************************************************************/
void blink() {
uint32_t color;
if ( curr_millis - last_LED_millis > 500 ) {
last_LED_millis = curr_millis;
ledState = !ledState;
if (ledState) {
//color = ws2812b.Color(0, 255, 0);
for ( int i = 0; i < NUM_PIXELS; i++ ) {
if ( i % 2 ) {
color = ws2812b.Color(0, 0, 0);
} else {
color = ws2812b.Color(0, 255, 0);
}
ws2812b.setPixelColor(i, color);
//ws2812b.setPixelColor(i, 0, 255, 0);
//leds[i] = CRGB::Red;
}
// Serial.println("BLINK ON");
} else {
//color = ws2812b.Color(0, 0, 0);
for ( int i = 0; i < NUM_PIXELS; i++ ) {
if ( i % 2 ) {
color = ws2812b.Color(0, 255, 0);
} else {
color = ws2812b.Color(0, 0, 0);
}
ws2812b.setPixelColor(i, color);
//ws2812b.setPixelColor(i, 0, 0, 0);
//leds[i] = CRGB::Black;
}
// Serial.println("BLINK OFF");
}
//ws2812b.fill(color, 0, NUM_PIXELS);
ws2812b.show();
//FastLED.show();
digitalWrite(PIN_LED, ledState);
}
}
/************************************************************************
Start - u8g2 CODE BASE
************************************************************************/
int aligncenter_H(String text) {
int newposy = (SCREEN_HEIGHT / 2) + ((u8g2.getAscent() - u8g2.getDescent()) / 2) - 1 ;
return newposy;
}
int aligncenter(int posx, String text) {
int newposx = posx - (u8g2.getUTF8Width(text.c_str()) / 2);
return newposx;
}
int alignright(int posx, String text) {
int newposx = posx - u8g2.getUTF8Width(text.c_str());
return newposx;
}
void drawFramedText(int x, int y, String text) {
int space = 3;
int text_w;
if ( text == "zur\374ck" ) {
text_w = u8g2.getUTF8Width("zuruck");
} else {
text_w = u8g2.getUTF8Width(text.c_str());
}
int text_h = u8g2.getAscent() - u8g2.getDescent();
// ***********************************************************************
// * DRAW FRAME
// ***********************************************************************
int frame_x = x - ( space + 1 ); // OK
int frame_y = y - u8g2.getAscent() - ( space + 1 ) ; // OK
int frame_width = text_w + ( 2 * space ) + 2; // OK
int frame_height = text_h + ( 2 * space ) + 1; // OK
u8g2.drawFrame(frame_x, frame_y, frame_width, frame_height);
// ***********************************************************************
// * DRAW STRING
// ***********************************************************************
int text_x = x;
int text_y = y;
u8g2.drawStr(text_x, text_y, text.c_str());
}
void drawFramedTextSelected(int x, int y, String text) {
int space = 1;
int text_w;
if ( text == "zur\374ck" ) {
text_w = u8g2.getUTF8Width("zuruck");
} else {
text_w = u8g2.getUTF8Width(text.c_str());
}
int text_h = u8g2.getAscent() - u8g2.getDescent();
// ***********************************************************************
// * DRAW FRAME
// ***********************************************************************
int frame_x = x - ( space + 1 ); // OK
int frame_y = y - u8g2.getAscent() - ( space + 1 ) ; // OK
int frame_width = text_w + ( 2 * space ) + 2; // OK
int frame_height = text_h + ( 2 * space ) + 1; // OK
u8g2.drawBox(frame_x, frame_y, frame_width, frame_height);
// ***********************************************************************
// * DRAW STRING
// ***********************************************************************
int text_x = x;
int text_y = y;
u8g2.setDrawColor(0);
u8g2.drawStr(text_x, text_y, text.c_str());
u8g2.setDrawColor(1);
}
void drawSelectedTextLine(int y, String text, int space) {
int text_w;
if ( text == "zur\374ck" ) {
text_w = u8g2.getUTF8Width("zuruck");
} else {
text_w = u8g2.getUTF8Width(text.c_str());
}
int text_h = u8g2.getAscent() - u8g2.getDescent();
// ***********************************************************************
// * DRAW FRAME
// ***********************************************************************
int radius = 3;
int frame_x = 0;
int frame_y = y - u8g2.getAscent() - ( space + 1 ) ; // OK
int frame_width = USABLE_SCREEN_WIDTH;
int frame_height = text_h + ( 2 * space ) + 1; // OK
u8g2.drawRFrame(frame_x, frame_y, frame_width, frame_height, radius);
// ***********************************************************************
// * DRAW STRING
// ***********************************************************************
int text_x = frame_x + space + 1;
int text_y = y;
u8g2.drawStr(text_x, text_y, text.c_str());
}
void drawScrollbar(int pos, int max_pos) {
int pixel_size = 1;
int bar_width = ( 2 * pixel_size ) + pixel_size;
int bar_height = SCREEN_HEIGHT / max_pos;
for (int i = 1; i < SCREEN_HEIGHT; i++) {
u8g2.drawBox(SCREEN_WIDTH - (2 * pixel_size), i, pixel_size, pixel_size);
i = i + pixel_size + 1;
}
u8g2.drawBox(SCREEN_WIDTH - bar_width, (bar_height * pos) - bar_height, bar_width, bar_height);
USABLE_SCREEN_WIDTH = SCREEN_WIDTH - bar_width - 1;
}
void drawWords(int xloc, int yloc /*bottom*/, const char *msg ) {
// display a string on multiple text lines, keeping words intact where possible,
// and accepting \n to force a new line
int dspwidth = u8g2.getDisplayWidth(); // display width in pixels
int strwidth = 0; // string width in pixels
char glyph[2]; glyph[1] = 0;
for (const char *ptr = msg, *lastblank = NULL; *ptr; ++ptr) {
while (xloc == 0 && (*msg == ' ' || *msg == '\n'))
if (ptr == msg++) ++ptr; // skip blanks and newlines at the left edge
glyph[0] = *ptr;
strwidth += u8g2.getStrWidth(glyph); // accumulate the pixel width
if (*ptr == ' ') lastblank = ptr; // remember where the last blank was
else ++strwidth; // non-blanks will be separated by one additional pixel
if (*ptr == '\n' || // if we found a newline character,
xloc + strwidth > dspwidth) { // or if we ran past the right edge of the display
int starting_xloc = xloc;
// print to just before the last blank, or to just before where we got to
while (msg < (lastblank ? lastblank : ptr)) {
glyph[0] = *msg++;
xloc += u8g2.drawStr(xloc, yloc, glyph);
}
strwidth -= xloc - starting_xloc; // account for what we printed
yloc += u8g2.getMaxCharHeight(); // advance to the next line
xloc = 0; lastblank = NULL;
}
}
while (*msg) { // print any characters left over
glyph[0] = *msg++;
xloc += u8g2.drawStr(xloc, yloc, glyph);
}
}
/************************************************************************
END - u8g2 CODE BASE
************************************************************************/
/************************************************************************
START - Menu CODE BASE
************************************************************************
UPDATE MENU
************************************************************************/
void updateMenu() {
switch (currMenu) {
case 1: // Show Cocktails Menu
CocktailMenu();
break;
case 2: // Show Setup Menu
SetupMenu();
break;
case 3:
ZutatenMenu();
break;
default: // Show DEFAULT MENU ( Main Menu )
mainMenu();
break;
}
}
/************************************************************************
MAIN MENU
************************************************************************/
void mainMenu() {
maxPos = 2;
rotaryEncoderAi.setBoundaries(minPos, maxPos, false);
uint8_t mi = 0;
//String menuItems[maxPos+1];
menuItems[mi] = "Hauptmen\374";
mi++;
if (NumCocktailsAvailable > 0) {
menuItems[mi] = "Cocktails";
mi++;
maxPos = 2;
} else {
maxPos = 1;
}
menuItems[mi] = "Setup";
u8g2.clearBuffer();
drawScrollbar(rotaryEncoderPos.Pos, maxPos);
u8g2.setFont(u8g2_font_tpss_tn);
u8g2.drawStr(aligncenter(USABLE_SCREEN_WIDTH / 2, menuItems[0]), 10, menuItems[0].c_str());
int mid_screen_pos = (SCREEN_HEIGHT / 2) + (u8g2.getAscent() / 2);
int mid_menu_pos = ((SCREEN_HEIGHT - 12) / 2) + (u8g2.getAscent() / 2) + 12;
if ( rotaryEncoderPos.Pos != 1 ) {
u8g2.drawStr(4, mid_menu_pos - 17, menuItems[rotaryEncoderPos.Pos - 1].c_str());
}
drawSelectedTextLine(mid_menu_pos, menuItems[rotaryEncoderPos.Pos], 3);
if ( rotaryEncoderPos.Pos != maxPos ) {
u8g2.drawStr(4, mid_menu_pos + 17, menuItems[rotaryEncoderPos.Pos + 1].c_str());
}
u8g2.sendBuffer();
}
/************************************************************************
COCKTAIL MENU
************************************************************************/
void CocktailMenu() {
maxPos = NumCocktailsAvailable + 1;
rotaryEncoderAi.setBoundaries(minPos, maxPos, circleValues);
menuItems[0] = "Cocktails";
uint8_t i = 1;
while (i < maxPos) {
for (int CocktailID = 0; CocktailID < NumCocktails; CocktailID++) {
if ( Cocktail[CocktailID].available ) {
menuItems[i] = Cocktail[CocktailID].CocktailName;
i++;
}
}
}
menuItems[maxPos] = "zur\374ck";
u8g2.clearBuffer();
drawScrollbar(rotaryEncoderPos.Pos, maxPos);
//u8g2.setFont(u8g2_font_7x14_tf);
u8g2.setFont(u8g2_font_tpss_tn);
u8g2.drawStr(aligncenter(USABLE_SCREEN_WIDTH / 2, menuItems[0]), 10, menuItems[0].c_str());
int mid_screen_pos = (SCREEN_HEIGHT / 2) + (u8g2.getAscent() / 2);
int mid_menu_pos = ((SCREEN_HEIGHT - 12) / 2) + (u8g2.getAscent() / 2) + 12;
if ( rotaryEncoderPos.Pos != 1 ) {
u8g2.drawStr(4, mid_menu_pos - 17, menuItems[rotaryEncoderPos.Pos - 1].c_str());
}
drawSelectedTextLine(mid_menu_pos, menuItems[rotaryEncoderPos.Pos], 3);
if ( rotaryEncoderPos.Pos != maxPos ) {
u8g2.drawStr(4, mid_menu_pos + 17, menuItems[rotaryEncoderPos.Pos + 1].c_str());
}
u8g2.sendBuffer();
}
/************************************************************************
Zutaten MENU
************************************************************************/
void ZutatenMenu() {
maxPos = NumIngredients + 2;
rotaryEncoderAi.setBoundaries(minPos, maxPos, circleValues);
menuItems[0] = "Zutaten";
uint8_t i = 1;
while (i < maxPos) {
for (int IngredientID = 0; IngredientID < NumIngredients; IngredientID++) {
menuItems[i] = Ingredient[IngredientID].IngredientName;
i++;
}
}
menuItems[maxPos - 1] = "reset";
menuItems[maxPos] = "zur\374ck";
u8g2.clearBuffer();
drawScrollbar(rotaryEncoderPos.Pos, maxPos);
u8g2.setFont(u8g2_font_tpss_tn);
u8g2.drawStr(aligncenter(USABLE_SCREEN_WIDTH / 2, menuItems[0]), 10, menuItems[0].c_str());
int mid_screen_pos = (SCREEN_HEIGHT / 2) + (u8g2.getAscent() / 2);
int mid_menu_pos = ((SCREEN_HEIGHT - 12) / 2) + (u8g2.getAscent() / 2) + 12;
if ( rotaryEncoderPos.Pos > 2 ) {
u8g2.setFont(u8g2_font_5x8_tf);
u8g2.drawStr(5, mid_menu_pos - 24, menuItems[rotaryEncoderPos.Pos - 2].c_str());
}
if ( rotaryEncoderPos.Pos != 1 ) {
u8g2.setFont(u8g2_font_6x10_tf);
u8g2.drawStr(4, mid_menu_pos - 15, menuItems[rotaryEncoderPos.Pos - 1].c_str());
}
u8g2.setFont(u8g2_font_7x14_tf);
drawSelectedTextLine(mid_menu_pos, menuItems[rotaryEncoderPos.Pos], 2);
if ( rotaryEncoderPos.Pos != maxPos ) {
u8g2.setFont(u8g2_font_6x10_tf);
u8g2.drawStr(4, mid_menu_pos + 12, menuItems[rotaryEncoderPos.Pos + 1].c_str());
}
if ( rotaryEncoderPos.Pos < maxPos - 1 ) {
u8g2.setFont(u8g2_font_5x8_tf);
u8g2.drawStr(5, mid_menu_pos + 20, menuItems[rotaryEncoderPos.Pos + 2].c_str());
}
u8g2.sendBuffer();
}
/************************************************************************
Setup MENU
************************************************************************/
void SetupMenu() {
maxPos = 5;
rotaryEncoderAi.setBoundaries(minPos, maxPos, circleValues);
//String menuItems[maxPos+1];
menuItems[0] = "Setup Men\374";
menuItems[1] = "Zutaten";
menuItems[2] = "Kalibrieren";
menuItems[3] = "Waage";
menuItems[4] = "Tara";
menuItems[5] = "zur\374ck";
u8g2.clearBuffer();
drawScrollbar(rotaryEncoderPos.Pos, maxPos);
u8g2.setFont(u8g2_font_tpss_tn);
u8g2.drawStr(aligncenter(USABLE_SCREEN_WIDTH / 2, menuItems[0]), 10, menuItems[0].c_str());
int mid_screen_pos = (SCREEN_HEIGHT / 2) + (u8g2.getAscent() / 2);
int mid_menu_pos = ((SCREEN_HEIGHT - 12) / 2) + (u8g2.getAscent() / 2) + 12;
if ( rotaryEncoderPos.Pos != 1 ) {
u8g2.drawStr(4, mid_menu_pos - 17, menuItems[rotaryEncoderPos.Pos - 1].c_str());
}
drawSelectedTextLine(mid_menu_pos, menuItems[rotaryEncoderPos.Pos], 3);
if ( rotaryEncoderPos.Pos != maxPos ) {
u8g2.drawStr(4, mid_menu_pos + 17, menuItems[rotaryEncoderPos.Pos + 1].c_str());
}
u8g2.sendBuffer();
}
/************************************************************************
END - Menu CODE BASE
************************************************************************/
/************************************************************************
START - BUTTON ACTIONS CODE BASE
************************************************************************/
/************************************************************************
BASIC ACTIONS
************************************************************************/
void longPressedButtonAction() {
if ( SERIAL_CONNECTED ) {
Serial.print(curr_millis);
Serial.println(" - Button Long Pressed.");
}
unpressButton();
}
void shortPressedButtonAction() {
if ( SERIAL_CONNECTED ) {
Serial.print(curr_millis);
Serial.println(" - Button short Pressed.");
}
unpressButton();
}
/************************************************************************
POUR COCTAIL
************************************************************************/
void pourCocktail(uint8_t CocktailID) {
unpressButton();
//noInterrupts();
String tmptxt;
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_tpss_tn);
u8g2.drawStr(aligncenter(SCREEN_WIDTH / 2, Cocktail[CocktailID].CocktailName), 10, Cocktail[CocktailID].CocktailName.c_str());
tmptxt = "Bitte Glas platzieren";
u8g2.setFont(u8g2_font_6x13_tf);
u8g2.drawStr(aligncenter(SCREEN_WIDTH / 2, tmptxt), aligncenter_H(tmptxt), tmptxt.c_str());
u8g2.sendBuffer();
float start_weight = 0.0;
float delay_weight = 10000.0;
float delta_weight = 10000.0;
start_weight = getChilledLoadCellValue();
if ( SERIAL_CONNECTED ) {
Serial.print("Start Gewicht: ");
Serial.print(start_weight);
Serial.println(" Gramm.");
}
//if ( start_weight < 0 ) start_weight = start_weight*-1;
delay(5000);
delay_weight = getChilledLoadCellValue();
if ( SERIAL_CONNECTED ) {
Serial.print("Delay Gewicht: ");
Serial.print(delay_weight);
Serial.println(" Gramm.");
}
//if ( delay_weight < 0 ) delay_weight = delay_weight*-1;
delta_weight = delay_weight - start_weight;
if ( SERIAL_CONNECTED ) {
Serial.print("Delta Gewicht: ");
Serial.println(delta_weight);
}
while ( delta_weight > 10 || delta_weight < -10 ) {
curr_millis = millis();
blink();
start_weight = delay_weight;
delay(50);
delay_weight = getChilledLoadCellValue();
delta_weight = delay_weight - start_weight;
if ( SERIAL_CONNECTED ) {
Serial.print("Delta Gewicht: ");
Serial.println(delta_weight);
}
}
if ( start_weight < 100.0 ) {
while (rotaryButton.ButtonPressed == false) {
curr_millis = millis();
blink();
UpdateButton();
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_tpss_tn);
u8g2.drawStr(aligncenter(SCREEN_WIDTH / 2, Cocktail[CocktailID].CocktailName), 10, Cocktail[CocktailID].CocktailName.c_str());
tmptxt = "Bitte Glas platzieren";
u8g2.setFont(u8g2_font_6x13_tf);
u8g2.drawStr(aligncenter(SCREEN_WIDTH / 2, tmptxt), aligncenter_H(tmptxt), tmptxt.c_str());
tmptxt = "OK";
drawFramedText(alignright(SCREEN_WIDTH - 4, tmptxt), SCREEN_HEIGHT - 5, tmptxt );
u8g2.sendBuffer();
}
unpressButton();
}
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_tpss_tn);
u8g2.drawStr(aligncenter(SCREEN_WIDTH / 2, Cocktail[CocktailID].CocktailName), 10, Cocktail[CocktailID].CocktailName.c_str());
tmptxt = "Waage tarieren";
u8g2.setFont(u8g2_font_6x13_tf);
u8g2.drawStr(aligncenter(SCREEN_WIDTH / 2, tmptxt), aligncenter_H(tmptxt), tmptxt.c_str());
tmptxt = "Bitte warten...";
u8g2.drawStr(alignright(SCREEN_WIDTH - 4, tmptxt), SCREEN_HEIGHT - 5, tmptxt.c_str());
u8g2.sendBuffer();
TaraLoadCellnoFeedback();
//getChilledLoadCellValue();
for (int var = 0; var < NumPumps; var++) {
if (Cocktail[CocktailID].IngredientAmount[var] && Cocktail[CocktailID].IngredientName[var] != "") {
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_tpss_tn);
u8g2.drawStr(aligncenter(SCREEN_WIDTH / 2, Cocktail[CocktailID].CocktailName), 10, Cocktail[CocktailID].CocktailName.c_str());
tmptxt = "wird zubereitet.";
u8g2.setFont(u8g2_font_6x13_tf);
u8g2.drawStr(aligncenter(SCREEN_WIDTH / 2, tmptxt), 25, tmptxt.c_str());
tmptxt = "/";
u8g2.setFont(u8g2_font_6x10_tf);
u8g2.drawStr(aligncenter((SCREEN_WIDTH / 2) - 6, tmptxt), 37, tmptxt.c_str());
tmptxt = String(Cocktail[CocktailID].IngredientAmount[var]) + "ml";
u8g2.setFont(u8g2_font_6x10_tf);
u8g2.drawStr(alignright((SCREEN_WIDTH / 2) + (5 * 6), tmptxt), 37, tmptxt.c_str());
u8g2.setFont(u8g2_font_6x10_tf);
u8g2.drawStr(aligncenter(SCREEN_WIDTH / 2, Cocktail[CocktailID].IngredientName[var]), 47, Cocktail[CocktailID].IngredientName[var].c_str());
tmptxt = "Bitte warten...";
u8g2.setFont(u8g2_font_6x13_tf);
u8g2.drawStr(0, SCREEN_HEIGHT, tmptxt.c_str());
u8g2.sendBuffer();
for (int pump = 0; pump < NumIngredients; pump++) {
if ( Ingredient[pump].IngredientName == Cocktail[CocktailID].IngredientName[var] ) {
powerPumpOn(Ingredient[pump].PumpID, Cocktail[CocktailID].IngredientAmount[var]);
}
}
} else {
if ( SERIAL_CONNECTED ) {
Serial.println("nothing to do...");
}
//break;
}
//delay(500);
}
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_tpss_tn);
u8g2.drawStr(aligncenter(USABLE_SCREEN_WIDTH / 2, Cocktail[CocktailID].CocktailName), 10, Cocktail[CocktailID].CocktailName.c_str());
tmptxt = "ist fertig.";
u8g2.setFont(u8g2_font_6x13_tf);
u8g2.drawStr(aligncenter(SCREEN_WIDTH / 2, tmptxt), aligncenter_H(tmptxt), tmptxt.c_str());
tmptxt = "Bitte entnehmen.";
u8g2.drawStr(aligncenter(SCREEN_WIDTH / 2, tmptxt), SCREEN_HEIGHT, tmptxt.c_str());
u8g2.sendBuffer();
static boolean newDataReady = 0;
float weight = 99999;
if ( SERIAL_CONNECTED ) {
Serial.print("Weight:");
Serial.println(weight);
Serial.println(getChilledLoadCellValue());
}
while ( weight > 0.0 ) {
curr_millis = millis();
blink();
weight = getChilledLoadCellValue();
delay(50);
}
TaraLoadCellnoFeedback();
unpressButton();
//interrupts();
}
/************************************************************************
END - BUTTON ACTIONS CODE BASE
************************************************************************/
/************************************************************************
TURN PUMP XY ON
************************************************************************/
void powerPumpOn(uint8_t PumpID, uint8_t Amount) {
int start_weight = 0;
start_weight = getChilledLoadCellValue();
if ( SERIAL_CONNECTED ) {
Serial.print("Turning Pump: ");
Serial.print(PumpID);
Serial.println(" on.");
Serial.print("pouring ");
Serial.print(Amount);
Serial.println("ml.");
}
int poured = 0;
int weight = 0;
int xpos = 110;
//void ControlPWM_SINGLE(uint8_t nr, uint8_t start, uint8_t ende, bool soft);
ControlPWM_SINGLE(PumpID - 1, 0, 100, false);
while ( poured < Amount ) {
weight = getLoadCellValue_noFeedback();
poured = weight - start_weight;
switch (poured) {
case 0 ... 9:
xpos = 110;
break;
case 10 ... 99:
xpos = 110 - 6;
break;
case 100 ... 999:
xpos = 110 - 12;
break;
case 1000 ... 9999:
xpos = 110 - 18;
break;
case -9 ... -1:
xpos = 110 - 6;
break;
case -99 ... -10:
xpos = 110 - 12;
break;
case -999 ... -100:
xpos = 110 - 18;
break;
case -9999 ... -1000:
xpos = 110 - 24;
break;
}
tmptxt = String(poured);
u8g2.setFont(u8g2_font_6x10_tf);
u8g2.drawStr(alignright((SCREEN_WIDTH / 2) - (2 * 6), tmptxt), 37, tmptxt.c_str());
u8g2.sendBuffer();
}
ControlPWM_SINGLE(PumpID - 1, 100, 0, false);
delay(1000);
}
void ControlPWM_SINGLE(uint8_t nr, uint8_t start, uint8_t ende, bool soft) {
if ( soft ) {
ledcAttach(PumpPIN[nr], PWMFreq, PWMResolution);
if ( start < ende ) {
for (int value = 0; value <= 100; value++) {
ControlPWMChannel(PumpPIN[nr], value);
delay(100);
}
} else {
for (int value = 100; value >= 0; value--) {
ControlPWMChannel(PumpPIN[nr], value);
delay(100);
}
}
} else {
//ControlPWMChannel(PumpPIN[nr], ende);
analogWrite(PumpPIN[nr], map(ende, 0, 100, 0, 255));
}
if ( ende == 0 ) {
ledcDetach(PumpPIN[nr]);
digitalWrite(PumpPIN[nr], LOW);
}
}
void ControlPWMChannel(uint8_t pin, uint8_t value) {
int dutyCycle = map(value, 0, 100, 0, MAX_DUTY_CYCLE);
ledcWrite(pin, dutyCycle);
}
/************************************************************************
checkCoctails
************************************************************************/
void checkCocktails() {
NumCocktailsAvailable = 0;
for (int CocktailID = 0; CocktailID < NumCocktails; CocktailID++) {
int soup = 0;
int soup2 = 0;
for (int var = 0; var < NumPumps; var++) {
if ( Cocktail[CocktailID].IngredientName[var] != "" ) {
soup++;
soup2++;
}
if ( Cocktail[CocktailID].IngredientAmount[var] ) {
soup--;
}
if ( soup > 0 ) {
Cocktail[CocktailID].available = false;
} else {
for (int pump = 0; pump < NumIngredients; pump++) {
if ( Ingredient[pump].IngredientName == Cocktail[CocktailID].IngredientName[var] ) {
if ( Ingredient[pump].PumpID > 0 ) soup2--;
}
}
}
}
if ( (soup > 0) || (soup2 > 0) ) {
Cocktail[CocktailID].available = false;
} else {
Cocktail[CocktailID].available = true;
NumCocktailsAvailable++;
}
}
NumCocktailsMenu = NumCocktailsAvailable + 1;
}
int getCockailIDbyName(String Name) {
uint8_t CocktailID = 0;
while (CocktailID < NumCocktails) {
if ( Cocktail[CocktailID].CocktailName == Name ) {
break;
}
CocktailID++;
}
return CocktailID;
}
int getIngredientIDbyName(String Name) {
uint8_t IngredientID = 0;
while (IngredientID < NumIngredients) {
if ( Ingredient[IngredientID].IngredientName == Name ) {
break;
}
IngredientID++;
}
return IngredientID;
}
/************************************************************************
Modify Ingredient
************************************************************************/
void modifyIngredient(uint8_t IngredientID) {
maxPos = 2;
rotaryEncoderAi.setBoundaries(minPos, maxPos, true);
rotaryEncoderPos.Pos = 1;
rotaryEncoderPos.PosLocked = rotaryEncoderPos.Pos;
rotaryEncoderAi.setEncoderValue(rotaryEncoderPos.Pos);
bool modify = false;
bool _resume = false;
int old_value = Ingredient[IngredientID].PumpID;
while ( !_resume ) {
curr_millis = millis();
blink();
UpdateButton();
// *******************************************
// Button Actions
// *******************************************
if ( rotaryEncoderPos.PosLocked == 1 && rotaryButton.ButtonPressed && !modify ) {
unpressButton();
modify = true;
rotaryEncoderPos.locked = true;
rotaryEncoderAi.setBoundaries(0, NumPumps, true);
rotaryEncoderPos.Pos = Ingredient[IngredientID].PumpID;
rotaryEncoderAi.setEncoderValue(rotaryEncoderPos.Pos);
} else if ( rotaryEncoderPos.PosLocked == 1 && rotaryButton.ButtonPressed && modify) {
unpressButton();
modify = false;
rotaryEncoderPos.locked = false;
Ingredient[IngredientID].PumpID = rotaryEncoderPos.Pos;
if ( checkIngredient() ) {
writeIngredients();
rotaryEncoderPos.PosLocked = 2;
old_value = Ingredient[IngredientID].PumpID;
} else {
Ingredient[IngredientID].PumpID = old_value;
rotaryEncoderPos.PosLocked = 1;
}
rotaryEncoderAi.setBoundaries(minPos, maxPos, true);
rotaryEncoderPos.Pos = rotaryEncoderPos.PosLocked;
rotaryEncoderAi.setEncoderValue(rotaryEncoderPos.Pos);
} else if ( rotaryEncoderPos.PosLocked == 2 && rotaryButton.ButtonPressed ) {
rotaryEncoderAi.setBoundaries(minPos, NumIngredients + 2, true);
unpressButton();
_resume = true;
}
// *******************************************
// PRINT DISPLAY
// *******************************************
if ( ((curr_millis - rotaryButton.LastButtonChange) < 60) || ((curr_millis - LastEncoderPosChange) < 60)) {
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_tpss_tn);
u8g2.drawStr(aligncenter(USABLE_SCREEN_WIDTH / 2, Ingredient[IngredientID].IngredientName), 10, Ingredient[IngredientID].IngredientName.c_str());
u8g2.setFont(u8g2_font_7x14_tf);
if ( rotaryEncoderPos.PosLocked == 1 && !modify ) {
drawFramedText(4, 30, "Pumpe: ");
//drawFramedTextSelected(4,30, "Pumpe: ");
} else {
u8g2.drawStr(4, 30, "Pumpe: ");
}
if (modify) {
u8g2.setFont(u8g2_font_7x14B_tf);
//drawFramedText(alignright(74, String(rotaryEncoderPos.Pos)), 30, String(rotaryEncoderPos.Pos));
drawFramedTextSelected(alignright(74, String(rotaryEncoderPos.Pos)), 30, String(rotaryEncoderPos.Pos));
} else {
u8g2.setFont(u8g2_font_7x14_tf);
u8g2.drawStr(alignright(74, String(Ingredient[IngredientID].PumpID)), 30, String(Ingredient[IngredientID].PumpID).c_str());
}
if (Ingredient[IngredientID].alcoholic) {
u8g2.setFont(u8g2_font_5x8_tf);
u8g2.drawStr(4, 42, "alkoholisch");
}
u8g2.setFont(u8g2_font_6x10_tf);
if ( rotaryEncoderPos.PosLocked == 2 ) {
drawFramedText(alignright(SCREEN_WIDTH - 4, "zuruck"), SCREEN_HEIGHT - 5, "zur\374ck" );
//drawFramedTextSelected(alignright(SCREEN_WIDTH-4, "zuruck"), SCREEN_HEIGHT-5, "zur\374ck" );
} else {
u8g2.drawStr(alignright(SCREEN_WIDTH - 4, "zuruck"), SCREEN_HEIGHT - 5, "zur\374ck");
}
u8g2.sendBuffer();
}
}
checkCocktails();
rotaryEncoderPos.Pos = rotaryEncoderPos.LastPos;
rotaryEncoderPos.PosLocked = rotaryEncoderPos.Pos;
rotaryEncoderAi.setEncoderValue(rotaryEncoderPos.Pos);
rotaryEncoderAi.reset(rotaryEncoderPos.LastPos);
/*
Serial.print("LastPos: ");
Serial.println(rotaryEncoderPos.LastPos);
Serial.print("Pos: ");
Serial.println(rotaryEncoderPos.Pos);
Serial.print("PosLocked: ");
Serial.println(rotaryEncoderPos.PosLocked);
*/
}
bool checkIngredient() {
/*
Serial.print("Anzahl Pumpen: ");
Serial.println(NumPumps);
*/
int anz[NumPumps];
for (int abc = 0; abc < NumPumps; abc++) {
/*
Serial.print(abc+1);
Serial.print(" / ");
Serial.print(NumPumps);
Serial.print(" - ");
*/
anz[abc] = 0;
for (int i = 0; i < NumIngredients; i++) {
/*
Serial.print(i);
Serial.print(" ");
*/
if ( Ingredient[i].PumpID == abc + 1 ) {
anz[abc]++;
}
}
/*
Serial.print("Pumpe Nr. ");
Serial.print(abc+1);
Serial.print(" ");
Serial.print(anz[abc]);
Serial.println("x");
*/
if ( anz[abc] > 1 ) {
//Serial.println(" - Oh oh oh.");
return false;
}
if ( abc == NumPumps - 1 ) {
//Serial.println(" - OK");
return true;
}
}
return false;
}
void resetIngredient() {
for (int i = 0; i < NumIngredients; i++) {
Ingredient[i].PumpID = 0;
}
writeIngredients();
checkCocktails();
}
/************************************************************************
START - ROTARY ENCODER CODE BASE
************************************************************************
READ ENCODER
************************************************************************/
void IRAM_ATTR readEncoderISR() {
rotaryEncoderAi.readEncoder_ISR();
if (rotaryEncoderAi.encoderChanged()) {
LastEncoderPosChange = millis();
rotaryEncoderPos.Pos = rotaryEncoderAi.readEncoder();
if (!rotaryEncoderPos.locked) rotaryEncoderPos.PosLocked = rotaryEncoderPos.Pos;
Serial.print("Value: ");
Serial.println(rotaryEncoderPos.Pos);
}
}
/************************************************************************
UpdateButton
************************************************************************/
void UpdateButton() {
static unsigned long lastTimeButtonDown = 0;
static bool wasButtonDown = false;
bool isEncoderButtonDown = rotaryEncoderAi.isEncoderButtonDown();
//isEncoderButtonDown = !isEncoderButtonDown; //uncomment this line if your button is reversed
if (isEncoderButtonDown) {
Serial.print("+"); //REMOVE THIS LINE IF YOU DONT WANT TO SEE
if (!wasButtonDown) {
//start measuring
lastTimeButtonDown = millis();
}
//else we wait since button is still down
wasButtonDown = true;
return;
}
//button is up
if (wasButtonDown) {
Serial.println(""); //REMOVE THIS LINE IF YOU DONT WANT TO SEE
//click happened, lets see if it was short click, long click or just too short
if (millis() - lastTimeButtonDown >= longPressAfterMiliseconds) {
rotaryButton.ButtonPressed = true;
rotaryButton.ButtonPressedLong = true;
} else if (millis() - lastTimeButtonDown >= shortPressAfterMiliseconds) {
rotaryButton.ButtonPressed = true;
rotaryButton.ButtonPressedLong = false;
}
rotaryButton.LastButtonChange = millis();
}
wasButtonDown = false;
}
/************************************************************************
unpressButton
************************************************************************/
void unpressButton() {
rotaryButton.ButtonPressed = false;
if (rotaryButton.ButtonPressedLong == true ) rotaryButton.ButtonPressedLong = false;
rotaryButton.LastButtonChange = curr_millis;
}
/************************************************************************
SerialDebug RotaryEncoder
************************************************************************/
void SerialDebug(uint8_t ButtonPressed) {
if ( SERIAL_CONNECTED ) {
Serial.print(curr_millis);
Serial.print(" - Reading: ");
switch (ButtonPressed) {
case 2:
Serial.print("pressed");
break;
case 3:
Serial.print("not pressed");
break;
default:
Serial.print(ButtonPressed);
break;
}
Serial.print(" - ButtonPressed: ");
Serial.print(rotaryButton.ButtonPressed);
Serial.print(" - LastButtonChange: ");
Serial.print(rotaryButton.LastButtonChange);
Serial.print(" - ButtonPressedFixed: ");
Serial.print(rotaryButton.ButtonPressedLong);
if (rotaryButton.ButtonPressedLong) {
Serial.print(" (long)");
} else {
Serial.print(" (short)");
}
Serial.print(" - Pos: ");
Serial.print(rotaryEncoderPos.Pos);
/*
if (rotaryEncoderPos.PosDir == 1) {
Serial.print(" - Rotated clockwise ⏩");
} else if (rotaryEncoderPos.PosDir == 2) {
Serial.print(" - Rotated counterclockwise ⏪");
}
*/
Serial.println();
}
}
/************************************************************************
END - ROTARY ENCODER CODE BASE
************************************************************************/
/************************************************************************
START - LOAD CELL CODE BASE
************************************************************************/
/************************************************************************
showLoadCellValue
************************************************************************/
void showLoadCellValue() {
static boolean newDataReady = 0;
while (rotaryButton.ButtonPressed == false) {
curr_millis = millis();
blink();
UpdateButton();
if (LoadCell.update()) newDataReady = true;
if (newDataReady) {
u8g2.clearBuffer();
tmptxt = "Waage";
u8g2.setFont(u8g2_font_tpss_tn);
u8g2.drawStr(aligncenter(SCREEN_WIDTH / 2, tmptxt), 10, tmptxt.c_str());
tmptxt = String(LoadCell.getData()) + "gr";
u8g2.setFont(u8g2_font_6x13_tf);
u8g2.drawStr(aligncenter(SCREEN_WIDTH / 2, tmptxt), aligncenter_H(tmptxt), tmptxt.c_str());
tmptxt = "zur\374ck";
u8g2.setFont(u8g2_font_6x13_tf);
drawFramedText(alignright(SCREEN_WIDTH - 4, "zuruck"), SCREEN_HEIGHT - 5, tmptxt );
u8g2.sendBuffer();
newDataReady = 0;
}
}
unpressButton();
}
/************************************************************************
getLoadCellValue
************************************************************************/
float getLoadCellValue() {
float weight;
static boolean newDataReady = 0;
boolean _resume = false;
while (_resume == false) {
if (LoadCell.update()) newDataReady = true;
if (newDataReady) {
weight = LoadCell.getData();
if ( SERIAL_CONNECTED ) {
Serial.print(curr_millis);
Serial.print(" - getLoadCellValue() - Weight: ");
Serial.println(weight);
}
newDataReady = 0;
_resume = true;
}
}
return weight;
}
float getLoadCellValue_noFeedback() {
float weight;
static boolean newDataReady = 0;
boolean _resume = false;
while (_resume == false) {
if (LoadCell.update()) newDataReady = true;
if (newDataReady) {
weight = LoadCell.getData();
newDataReady = 0;
_resume = true;
}
}
return weight;
}
/************************************************************************
getChilledLoadCellValue
************************************************************************/
float getChilledLoadCellValue() {
float start_weight = 0.0;
float delay_weight = 1000.0;
float delta_weight;
delta_weight = delay_weight - start_weight;
float weight;
static boolean newDataReady = 0;
boolean _resume = false;
while (_resume == false) {
curr_millis = millis();
if (LoadCell.update()) newDataReady = true;
if (newDataReady) {
start_weight = delay_weight;
delay_weight = LoadCell.getData();
if ( delay_weight < 0 ) delay_weight * -1;
if ( delay_weight < start_weight ) {
delta_weight = start_weight - delay_weight;
} else {
delta_weight = delay_weight - start_weight;
}
if ( delta_weight < 10 ) {
weight = LoadCell.getData();
_resume = true;
}
newDataReady = 0;
}
delay(100);
}
return weight;
}
/************************************************************************
TaraLoadCell
************************************************************************/
void TaraLoadCell() {
maxPos = 2;
rotaryEncoderAi.setBoundaries(minPos, maxPos, false);
rotaryEncoderPos.Pos = 1;
rotaryEncoderAi.setEncoderValue(rotaryEncoderPos.Pos);
boolean _resume = false;
while (_resume == false) {
curr_millis = millis();
blink();
LoadCell.update();
UpdateButton();
u8g2.clearBuffer();
tmptxt = "Waage";
u8g2.setFont(u8g2_font_tpss_tn);
u8g2.drawStr(aligncenter(SCREEN_WIDTH / 2, tmptxt), 10, tmptxt.c_str());
if ( !rotaryButton.ButtonPressed ) {
tmptxt = "Waage nullen?";
u8g2.setFont(u8g2_font_6x13_tf);
u8g2.drawStr(aligncenter(SCREEN_WIDTH / 2, tmptxt), aligncenter_H(tmptxt), tmptxt.c_str());
if ( rotaryEncoderPos.Pos == 1 ) {
tmptxt = "Ja";
drawFramedText(4, SCREEN_HEIGHT - 5, tmptxt );
tmptxt = "Nein";
u8g2.drawStr(alignright(SCREEN_WIDTH - 4, tmptxt), SCREEN_HEIGHT - 5, tmptxt.c_str());
} else {
tmptxt = "Ja";
u8g2.drawStr(4, SCREEN_HEIGHT - 5, tmptxt.c_str());
tmptxt = "Nein";
drawFramedText(alignright(SCREEN_WIDTH - 4, tmptxt), SCREEN_HEIGHT - 5, tmptxt );
}
u8g2.sendBuffer();
} else {
unpressButton();
if ( rotaryEncoderPos.Pos == 1 ) {
tmptxt = "Waage wird genullt.";
u8g2.setFont(u8g2_font_6x13_tf);
u8g2.drawStr(aligncenter(SCREEN_WIDTH / 2, tmptxt), aligncenter_H(tmptxt), tmptxt.c_str());
tmptxt = "bitte warten...";
u8g2.setFont(u8g2_font_6x13_tf);
u8g2.drawStr(4, SCREEN_HEIGHT - 5, tmptxt.c_str());
u8g2.sendBuffer();
LoadCell.tare();
delay(500);
u8g2.clearBuffer();
tmptxt = "Waage";
u8g2.setFont(u8g2_font_tpss_tn);
u8g2.drawStr(aligncenter(SCREEN_WIDTH / 2, tmptxt), 10, tmptxt.c_str());
tmptxt = "Waage genullt.";
u8g2.setFont(u8g2_font_6x13_tf);
u8g2.drawStr(aligncenter(SCREEN_WIDTH / 2, tmptxt), aligncenter_H(tmptxt), tmptxt.c_str());
u8g2.sendBuffer();
delay(1000);
_resume = true;
} else {
_resume = true;
}
}
}
unpressButton();
rotaryEncoderPos.Pos = rotaryEncoderPos.LastPos;
rotaryEncoderAi.setEncoderValue(rotaryEncoderPos.LastPos);
}
void TaraLoadCellnoFeedback() {
LoadCell.tareNoDelay();
boolean _resume = false;
if ( SERIAL_CONNECTED ) {
Serial.println("Starting Tara.");
}
while (_resume == false) {
LoadCell.update();
if (LoadCell.getTareStatus() == true) {
if ( SERIAL_CONNECTED ) {
Serial.println("Tare complete");
}
_resume = true;
}
}
}
/************************************************************************
calibrateLoadCell
************************************************************************/
void calibrateLoadCell() {
maxPos = 2;
rotaryEncoderAi.setBoundaries(minPos, maxPos, false);
rotaryEncoderPos.Pos = 1;
rotaryEncoderAi.setEncoderValue(rotaryEncoderPos.Pos);
boolean _resume = false;
while (_resume == false) {
curr_millis = millis();
blink();
LoadCell.update();
UpdateButton();
u8g2.clearBuffer();
tmptxt = "Waage kalibrieren";
u8g2.setFont(u8g2_font_tpss_tn);
u8g2.drawStr(aligncenter(SCREEN_WIDTH / 2, tmptxt), 10, tmptxt.c_str());
if ( !rotaryButton.ButtonPressed ) {
//drawWords(0, 20, "Remove any load applied to the load cell.");
u8g2.setFont(u8g2_font_6x10_tf);
u8g2.drawStr(0, 22, "Bitte alle Gewichte");
u8g2.drawStr(0, 22 + 10, "von der Waage");
u8g2.drawStr(0, 22 + 10 + 10, "entfernen.");
if ( rotaryEncoderPos.Pos == 1 ) {
tmptxt = "Start";
drawFramedText(4, SCREEN_HEIGHT - 5, tmptxt );
tmptxt = "Abbrechen";
u8g2.drawStr(alignright(SCREEN_WIDTH - 4, tmptxt), SCREEN_HEIGHT - 5, tmptxt.c_str());
} else {
tmptxt = "Start";
u8g2.drawStr(4, SCREEN_HEIGHT - 5, tmptxt.c_str());
tmptxt = "Abbrechen";
drawFramedText(alignright(SCREEN_WIDTH - 4, tmptxt), SCREEN_HEIGHT - 5, tmptxt );
}
u8g2.sendBuffer();
} else {
unpressButton();
if ( rotaryEncoderPos.Pos == 1 ) {
tmptxt = "bitte warten...";
u8g2.drawStr(4, aligncenter_H(tmptxt), tmptxt.c_str());
u8g2.sendBuffer();
LoadCell.tare();
delay(500);
u8g2.clearBuffer();
tmptxt = "Waage kalibrieren";
u8g2.setFont(u8g2_font_tpss_tn);
u8g2.drawStr(aligncenter(SCREEN_WIDTH / 2, tmptxt), 10, tmptxt.c_str());
tmptxt = "Waage genullt.";
u8g2.setFont(u8g2_font_6x13_tf);
u8g2.drawStr(aligncenter(SCREEN_WIDTH / 2, tmptxt), aligncenter_H(tmptxt), tmptxt.c_str());
u8g2.sendBuffer();
delay(500);
_resume = true;
} else {
unpressButton();
return;
}
}
}
u8g2.clearBuffer();
tmptxt = "Waage kalibrieren";
u8g2.setFont(u8g2_font_tpss_tn);
u8g2.drawStr(aligncenter(SCREEN_WIDTH / 2, tmptxt), 10, tmptxt.c_str());
u8g2.setFont(u8g2_font_6x13_tf);
drawWords(0, 30, "Referenz Gewicht auf die Waage legen.");
u8g2.sendBuffer();
while ( getLoadCellValue_noFeedback() < 10 ) {
curr_millis = millis();
blink();
delay(50);
}
maxPos = 5000;
rotaryEncoderAi.setBoundaries(rotaryEncoderMinValue, rotaryEncoderMaxValue, circleValues);
rotaryEncoderPos.Pos = 50;
rotaryEncoderAi.setEncoderValue(rotaryEncoderPos.Pos);
rotaryEncoderAi.setAcceleration(250);
u8g2.clearBuffer();
tmptxt = "Waage kalibrieren";
u8g2.setFont(u8g2_font_tpss_tn);
u8g2.drawStr(aligncenter(SCREEN_WIDTH / 2, tmptxt), 10, tmptxt.c_str());
tmptxt = "Gewicht:";
u8g2.setFont(u8g2_font_6x13_tf);
u8g2.drawStr(0, (SCREEN_HEIGHT / 2) + (u8g2.getAscent() / 2), tmptxt.c_str());
u8g2.sendBuffer();
int known_mass = 0;
_resume = false;
while (_resume == false) {
curr_millis = millis();
blink();
UpdateButton();
LoadCell.update();
tmptxt = String(rotaryEncoderPos.Pos) + "g";
u8g2.setFont(u8g2_font_6x13_tf);
u8g2.drawStr(alignright(SCREEN_WIDTH - 30, tmptxt), (SCREEN_HEIGHT / 2) + (u8g2.getAscent() / 2), tmptxt.c_str());
u8g2.sendBuffer();
if ( rotaryButton.ButtonPressed ) {
known_mass = rotaryEncoderPos.Pos;
unpressButton();
_resume = true;
}
}
u8g2.clearBuffer();
tmptxt = "Waage kalibrieren";
u8g2.setFont(u8g2_font_tpss_tn);
u8g2.drawStr(aligncenter(SCREEN_WIDTH / 2, tmptxt), 10, tmptxt.c_str());
tmptxt = "bitte warten...";
u8g2.setFont(u8g2_font_6x13_tf);
u8g2.drawStr(aligncenter(SCREEN_WIDTH / 2, tmptxt), (SCREEN_HEIGHT / 2) + (u8g2.getAscent() / 2), tmptxt.c_str());
u8g2.sendBuffer();
delay(500);
LoadCell.refreshDataSet(); //refresh the dataset to be sure that the known mass is measured correct
float newCalibrationValue = LoadCell.getNewCalibration(known_mass); //get the new calibration value
#if defined(ESP8266)|| defined(ESP32)
EEPROM.begin(512);
#endif
EEPROM.put(calVal_eepromAdress, newCalibrationValue);
#if defined(ESP8266)|| defined(ESP32)
EEPROM.commit();
#endif
EEPROM.get(calVal_eepromAdress, newCalibrationValue);
u8g2.clearBuffer();
tmptxt = "Waage kalibrieren";
u8g2.setFont(u8g2_font_tpss_tn);
u8g2.drawStr(aligncenter(SCREEN_WIDTH / 2, tmptxt), 10, tmptxt.c_str());
tmptxt = "New calibration value has been saved and set to: " + String(newCalibrationValue);
u8g2.setFont(u8g2_font_6x13_tf);
drawWords(0, 24, tmptxt.c_str());
u8g2.sendBuffer();
delay(500);
/*
tmptxt = "gespeichert.";
u8g2.setFont(u8g2_font_6x13_tf);
u8g2.drawStr(aligncenter(SCREEN_WIDTH / 2, tmptxt), SCREEN_HEIGHT - 2, tmptxt.c_str());
u8g2.sendBuffer();
delay(500);
*/
rotaryEncoderAi.disableAcceleration();
rotaryEncoderPos.Pos = rotaryEncoderPos.LastPos;
rotaryEncoderAi.setEncoderValue(rotaryEncoderPos.LastPos);
}
/************************************************************************
changeSavedLoadCellCalFactor
************************************************************************/
void changeSavedCalFactor_serial() {
float oldCalibrationValue = LoadCell.getCalFactor();
boolean _resume = false;
Serial.println("***");
Serial.print("Current value is: ");
Serial.println(oldCalibrationValue);
Serial.println("Now, send the new value from serial monitor, i.e. 696.0");
float newCalibrationValue;
while (_resume == false) {
if (Serial.available() > 0) {
newCalibrationValue = Serial.parseFloat();
if (newCalibrationValue != 0) {
Serial.print("New calibration value is: ");
Serial.println(newCalibrationValue);
LoadCell.setCalFactor(newCalibrationValue);
_resume = true;
}
}
}
_resume = false;
Serial.print("Save this value to EEPROM adress ");
Serial.print(calVal_eepromAdress);
Serial.println("? y/n");
while (_resume == false) {
if (Serial.available() > 0) {
char inByte = Serial.read();
if (inByte == 'y') {
#if defined(ESP8266)|| defined(ESP32)
EEPROM.begin(512);
#endif
EEPROM.put(calVal_eepromAdress, newCalibrationValue);
#if defined(ESP8266)|| defined(ESP32)
EEPROM.commit();
#endif
EEPROM.get(calVal_eepromAdress, newCalibrationValue);
Serial.print("Value ");
Serial.print(newCalibrationValue);
Serial.print(" saved to EEPROM address: ");
Serial.println(calVal_eepromAdress);
_resume = true;
}
else if (inByte == 'n') {
Serial.println("Value not saved to EEPROM");
_resume = true;
}
}
}
Serial.println("End change calibration value");
Serial.println("***");
}
/************************************************************************
END - LOAD CELL CODE BASE
************************************************************************/
/************************************************************************
START - SD CARD CODE BASE
************************************************************************/
void printDirectory(File dir, int numTabs) {
while (true) {
File entry = dir.openNextFile();
if (! entry) {
// no more files
break;
}
for (uint8_t i = 0; i < numTabs; i++) {
Serial.print('\t');
}
Serial.print(entry.name());
if (entry.isDirectory()) {
Serial.println("/");
printDirectory(entry, numTabs + 1);
} else {
// files have sizes, directories do not
Serial.print("\t\t");
Serial.println(entry.size(), DEC);
}
entry.close();
}
}
void sdcardcontent() {
Serial.println("Files in the card:");
File root;
root = SD.open("/");
printDirectory(root, 0);
Serial.println("");
// Example of reading file from the card:
File textFile = SD.open("/wokwi.txt");
if (textFile) {
Serial.print("wokwi.txt: ");
while (textFile.available()) {
Serial.write(textFile.read());
}
textFile.close();
Serial.println();
} else {
Serial.println("error opening wokwi.txt!");
}
}
void readIngredients() {
File textFile = SD.open("/Ingredients.csv");
if (textFile) {
if ( SERIAL_CONNECTED ) {
Serial.println("reading Ingredients from: Ingredients.csv: ");
}
int line = 0;
int field = 0;
int lastfield = 0;
String str = "";
while (textFile.available()) {
char c = textFile.read();
if (c == '\r' ) {
if ( SERIAL_CONNECTED ) Serial.println("Char <Return Line> found: -r - ignored.");
} else if ( c == '\n' ) { // NEW LINE
if ( SERIAL_CONNECTED ) Serial.println("Char <New Line> found: -n");
if ( str.toInt() == 0 ) {
Ingredient[line - 1].alcoholic = false;
} else {
Ingredient[line - 1].alcoholic = true;
}
line++;
Serial.println(line);
field = 0;
str = "";
} else if (c == ',' || c == ';') { // NEW COLUMN
if ( line > 0 ) {
switch (field) {
case 0:
Ingredient[line - 1].PumpID = str.toInt();
break;
case 1:
Ingredient[line - 1].IngredientName = str;
break;
case 2:
if ( str.toInt() == 0 ) {
Ingredient[line - 1].alcoholic = false;
} else {
Ingredient[line - 1].alcoholic = true;
}
break;
}
}
str = "";
field++;
} else {
str += c;
}
}
textFile.close();
NumIngredients = line - 1;
} else {
if ( SERIAL_CONNECTED ) {
Serial.println("error opening Ingredients.csv!");
Serial.println("Loading Default Ingredients");
}
for ( int i = 0; i < NumDefaultIngredients; i++ ) {
Ingredient[i].PumpID = DefaultIngredient[i].PumpID;
Ingredient[i].IngredientName = DefaultIngredient[i].IngredientName;
Ingredient[i].alcoholic = DefaultIngredient[i].alcoholic;
}
NumIngredients = NumDefaultIngredients;
}
if ( SERIAL_CONNECTED ) {
Serial.print("Anzahl Zutaten: ");
Serial.println(NumIngredients);
Serial.println("----------------------------------------");
for (int i = 0; i < NumIngredients; i++) {
Serial.print(i + 1);
Serial.print("/");
Serial.print(NumIngredients);
Serial.print(" Zutaten: ");
Serial.print(Ingredient[i].IngredientName);
Serial.print(" - Pumpe: ");
Serial.print(Ingredient[i].PumpID);
Serial.print(" - alkoholisch: ");
Serial.println(Ingredient[i].alcoholic);
}
Serial.println("----------------------------------------");
}
}
void writeIngredients() {
if ( SD.exists("/Ingredients.csv") ) {
if ( SERIAL_CONNECTED ) {
Serial.println("Deleting... Ingredients.csv");
}
SD.remove("/Ingredients.csv");
if ( SD.exists("/Ingredients.csv") ) {
Serial.println("deleted");
} else {
Serial.println("not deleted");
}
} else {
Serial.println("file does not exsits.");
}
File myFile = SD.open("/Ingredients.csv", FILE_WRITE);
if ( SD.exists("/Ingredients.csv") ) {
Serial.println("file created.");
Serial.print("Size: ");
Serial.println(myFile.size());
} else {
Serial.println("file not created.");
}
if (myFile) {
myFile.seek(0);
myFile.println("PumpID,IngredientName,alcoholic");
if ( SERIAL_CONNECTED ) {
Serial.println("PumpID,IngredientName,alcoholic");
}
for (int i = 0; i < NumIngredients; i++) {
myFile.print(String(Ingredient[i].PumpID));
myFile.print(",");
myFile.print(Ingredient[i].IngredientName);
myFile.print(",");
if (DefaultIngredient[i].alcoholic) {
myFile.println("1");
} else {
myFile.println("0");
}
if ( SERIAL_CONNECTED ) {
Serial.print("VALUES: ");
Serial.print(Ingredient[i].PumpID);
Serial.print(",");
Serial.print(Ingredient[i].IngredientName);
Serial.print(",");
Serial.println(Ingredient[i].alcoholic);
}
myFile.flush();
}
myFile.close();
} else {
if ( SERIAL_CONNECTED ) {
Serial.println("Can't write to file.");
}
}
// Example of reading file from the card:
File textFile = SD.open("/Ingredients.csv");
if (textFile) {
Serial.print("Ingredients2.csv: ");
while (textFile.available()) {
Serial.write(textFile.read());
}
textFile.close();
Serial.println();
} else {
Serial.println("error opening Ingredients.csv!");
}
}
void readCocktails() {
File textFile = SD.open("/Cocktails.csv");
if (textFile) {
if ( SERIAL_CONNECTED ) {
Serial.println("reading Ingredients from: Cocktails.csv: ");
}
int line = 0;
int field = 0;
int ID = 0;
int zut = 0;
String str = "";
String tmpstr = str;
while (textFile.available()) {
char c = textFile.read();
if (c == '\r' ) {
if ( SERIAL_CONNECTED ) Serial.println("Char <Return Line> found: -r - ignored.");
} else if ( c == '\n' ) { // NEW LINE
if ( tmpstr == "COCKTAIL" ) {
Cocktail[ID].CocktailName = str;
} else if ( tmpstr == "ZUTAT" ) {
Cocktail[ID].IngredientName[zut] = str;
zut++;
} else if ( tmpstr == "MENGE" ) {
Cocktail[ID].IngredientAmount[zut] = str.toInt();
zut++;
ID++;
}
str = "";
field = 0;
} else if (c == ',' || c == ';') { // NEW COLUMN
if (field == 0 ) {
tmpstr = str;
zut = 0;
} else {
if ( tmpstr == "COCKTAIL" ) {
Cocktail[ID].CocktailName = str;
} else if ( tmpstr == "ZUTAT" ) {
Cocktail[ID].IngredientName[zut] = str;
zut++;
} else if ( tmpstr == "MENGE" ) {
Cocktail[ID].IngredientAmount[zut] = str.toInt();
zut++;
}
}
str = "";
field++;
} else {
str += c;
}
}
textFile.close();
NumCocktails = ID;
} else {
if ( SERIAL_CONNECTED ) {
Serial.println("error opening Cocktails.csv!");
}
int i = 0;
while ( DefaultCocktail[i].CocktailName ) {
Cocktail[i].CocktailName = DefaultCocktail[i].CocktailName;
for ( int z = 0; z < NumPumps; z++ ) {
if ( DefaultCocktail[i].IngredientAmount[z] > 0) {
Cocktail[i].IngredientName[z] = DefaultCocktail[i].IngredientName[z];
Cocktail[i].IngredientAmount[z] = DefaultCocktail[i].IngredientAmount[z];
}
}
i++;
}
NumCocktails = i - 1;
}
showAllCocktails();
}
void showAllCocktails() {
if ( SERIAL_CONNECTED ) {
Serial.println("----------------------------------------");
Serial.print("Anzahl Cocktails Rezepte: ");
Serial.println(NumCocktails);
Serial.print("Anzahl Cocktails Verfügbar: ");
Serial.println(NumCocktailsAvailable);
Serial.println("----------------------------------------");
for (int i = 0; i < NumCocktails; i++) {
Serial.print(i + 1);
Serial.print("/");
Serial.println(NumCocktails);
Serial.print(" - Cocktail: ");
Serial.println(Cocktail[i].CocktailName);
Serial.println(" - Zutaten: ");
for ( int z = 0; z < NumPumps; z++ ) {
if ( Cocktail[i].IngredientAmount[z] > 0) {
Serial.print(" - ");
Serial.print(Cocktail[i].IngredientAmount[z]);
Serial.print("ml ");
Serial.println(Cocktail[i].IngredientName[z]);
}
}
}
}
}
void showAvailableCocktails() {
if ( SERIAL_CONNECTED ) {
Serial.println("----------------------------------------");
Serial.print("Anzahl Cocktails Rezepte: ");
Serial.println(NumCocktails);
Serial.print("Anzahl Cocktails Verfügbar: ");
Serial.println(NumCocktailsAvailable);
Serial.println("----------------------------------------");
for (int i = 0; i < NumCocktails; i++) {
if (Cocktail[i].available) {
Serial.print(i + 1);
Serial.print("/");
Serial.println(NumCocktails);
Serial.print(" - Cocktail: ");
Serial.println(Cocktail[i].CocktailName);
Serial.println(" - Zutaten: ");
for ( int z = 0; z < NumPumps; z++ ) {
if ( Cocktail[i].IngredientAmount[z] > 0) {
Serial.print(" - ");
Serial.print(Cocktail[i].IngredientAmount[z]);
Serial.print("ml ");
Serial.println(Cocktail[i].IngredientName[z]);
}
}
}
}
}
}
/************************************************************************
END - SD CARD CODE BASE
************************************************************************/
/************************************************************************
END - FUNCTIONS
************************************************************************/
/************************************************************************
SETUP LOOP
************************************************************************/
void setup() {
// ***********************************
// * Pumps
// ***********************************
for ( int i = 0; i < NumPumps; i++) {
pinMode(PumpPIN[i], OUTPUT);
digitalWrite(PumpPIN[i], LOW);
}
// ***********************************
// * Serial Interface INITIALIZATION
// ***********************************
Serial.begin(115200);
delay(100);
// ***********************************
int i = 0;
while (!Serial) {
delay(10);
i++;
if ( i >= 100 ) {
break;
}
}
// ***********************************
if (Serial) {
SERIAL_CONNECTED = true;
Serial.println("Serial console connected.");
Serial.println("Starting...");
} else {
SERIAL_CONNECTED = false;
}
// ***********************************
SERIAL_CONNECTED = true;
// ***********************************
if ( SERIAL_CONNECTED ) {
Serial.print("MOSI: ");
Serial.println(MOSI); // 23
Serial.print("MISO: ");
Serial.println(MISO); // 19
Serial.print("SCK: ");
Serial.println(SCK); // 18
Serial.print("SS: ");
Serial.println(SS); // 5
Serial.print("SDA: ");
Serial.println(SDA); // 21
Serial.print("SCL: ");
Serial.println(SCL); // 22
Serial.print("TX: ");
Serial.println(TX); // ??
Serial.print("RX: ");
Serial.println(RX); // ??
}
// ***********************************
// * Configure PINs
// ***********************************
// * LED
// ***********************************
pinMode (PIN_LED, OUTPUT);
pinMode (PIN_WS2812B, OUTPUT);
//Serial.print("NUM_PIXELS: ");
//Serial.println(NUM_PIXELS);
ws2812b.begin();
ws2812b.clear();
//FastLED.addLeds<NEOPIXEL, PIN_WS2812B>(leds, NUM_PIXELS);
// ***********************************
// * OLED DISPLAY (u8g2) INITIALIZATION
// ***********************************
if (!u8g2.begin()) {
if ( SERIAL_CONNECTED ) {
Serial.println(F("SSD1306 allocation failed"));
}
for (;;); // Don't proceed, loop forever
}
//u8g2.setColorIndex(1); // set the color to white
//u8g2.setBitmapMode(1);
// ***********************************
SCREEN_WIDTH = u8g2.getDisplayWidth();
SCREEN_HEIGHT = u8g2.getDisplayHeight();
USABLE_SCREEN_WIDTH = SCREEN_WIDTH;
// ***********************************
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_7x14B_tf);
tmptxt = "Booting...";
u8g2.drawStr(aligncenter(SCREEN_WIDTH / 2, tmptxt), 10, tmptxt.c_str());
u8g2.sendBuffer();
// ***********************************
// * SD CARD INITIALIZATION
// ***********************************
if (!SD.begin(SD_CS_PIN)) {
if ( SERIAL_CONNECTED ) Serial.println("SD Card initialization failed!");
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_7x14B_tf);
tmptxt = "Booting...";
u8g2.drawStr(aligncenter(SCREEN_WIDTH / 2, tmptxt), 10, tmptxt.c_str());
u8g2.setFont(u8g2_font_6x10_tf);
drawWords(0, 30, "SD Card initialization failed!");
u8g2.sendBuffer();
while (true);
} else {
if ( SERIAL_CONNECTED ) Serial.println("SD Card initialization done.");
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_7x14B_tf);
tmptxt = "Booting...";
u8g2.drawStr(aligncenter(SCREEN_WIDTH / 2, tmptxt), 10, tmptxt.c_str());
u8g2.setFont(u8g2_font_6x10_tf);
drawWords(0, 30, "SD Card initialization done.");
u8g2.sendBuffer();
delay(500);
}
// ***********************************
// * LOAD CELL INITIALIZATION
// ***********************************
LoadCell.begin();
LoadCell.powerDown();
LoadCell.begin();
//LoadCell.setReverseOutput(); //uncomment to turn a negative output value to positive
unsigned long stabilizingtime = 2000; // preciscion right after power-up can be improved by adding a few seconds of stabilizing time
boolean _tare = true; //set this to false if you don't want tare to be performed in the next step
LoadCell.start(stabilizingtime, _tare);
if (LoadCell.getTareTimeoutFlag() || LoadCell.getSignalTimeoutFlag()) {
if ( SERIAL_CONNECTED ) Serial.println("Timeout, check MCU>HX711 wiring and pin designations");
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_7x14B_tf);
tmptxt = "Booting...";
u8g2.drawStr(aligncenter(SCREEN_WIDTH / 2, tmptxt), 10, tmptxt.c_str());
u8g2.setFont(u8g2_font_6x10_tf);
drawWords(0, 30, "Timeout, check MCU>HX711 wiring and pin designations");
u8g2.sendBuffer();
for (;;); // Don't proceed, loop forever
} else {
float calibrationValue; // calibration value (see example file "Calibration.ino")
calibrationValue = 0.42; // uncomment this if you want to set the calibration value in the sketch
#if defined(ESP8266)|| defined(ESP32)
Serial.println("ESP8266 or ESP32 found.");
EEPROM.begin(512); // uncomment this if you use ESP8266/ESP32 and want to fetch the calibration value from eeprom
#endif
EEPROM.get(calVal_eepromAdress, calibrationValue); // uncomment this if you want to fetch the calibration value from eeprom
if (calibrationValue > 0) {
if ( SERIAL_CONNECTED ) {
Serial.print("Calibration Value from EEPROM: ");
Serial.println(calibrationValue);
}
} else {
calibrationValue = 0.42;
if ( SERIAL_CONNECTED ) {
Serial.print("Calibration Value from SKETCH: ");
Serial.println(calibrationValue);
}
EEPROM.put(calVal_eepromAdress, calibrationValue);
#if defined(ESP8266)|| defined(ESP32)
EEPROM.commit();
#endif
EEPROM.get(calVal_eepromAdress, calibrationValue);
if ( SERIAL_CONNECTED ) {
Serial.print("Calibration Value stored: ");
Serial.println(calibrationValue);
}
}
LoadCell.setCalFactor(calibrationValue);
if ( SERIAL_CONNECTED ) {
Serial.println("HX711 initialization done");
}
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_7x14B_tf);
tmptxt = "Booting...";
u8g2.drawStr(aligncenter(SCREEN_WIDTH / 2, tmptxt), 10, tmptxt.c_str());
u8g2.setFont(u8g2_font_6x10_tf);
drawWords(0, 30, "HX711 initialization done");
u8g2.sendBuffer();
delay(500);
while (!LoadCell.update());
}
// ***********************************
// * READ INGREDIENTS
// ***********************************
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_7x14B_tf);
tmptxt = "Booting...";
u8g2.drawStr(aligncenter(SCREEN_WIDTH / 2, tmptxt), 10, tmptxt.c_str());
u8g2.setFont(u8g2_font_6x10_tf);
drawWords(0, 30, "loading Ingredients...");
u8g2.sendBuffer();
readIngredients();
delay(500);
// ***********************************
// * CHECK INGREDIENTS
// ***********************************
if (!checkIngredient()) {
if ( SERIAL_CONNECTED ) Serial.println("something went wrong");
}
// ***********************************
// * READ COCKTAILS
// ***********************************
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_7x14B_tf);
tmptxt = "Booting...";
u8g2.drawStr(aligncenter(SCREEN_WIDTH / 2, tmptxt), 10, tmptxt.c_str());
u8g2.setFont(u8g2_font_6x10_tf);
drawWords(0, 30, "loading Cocktails...");
u8g2.sendBuffer();
readCocktails();
delay(500);
// ***********************************
// * CHECK AVAILABLE COCKTAILS
// ***********************************
checkCocktails();
showAvailableCocktails();
//***********************************
// * CHECK INTERRUPTs
// ***********************************
/*
if (digitalPinToInterrupt(ENCODER_CLK) == -1) {
if ( SERIAL_CONNECTED ) {
Serial.print("ENCODER_CLK: ");
Serial.print(ENCODER_CLK);
Serial.println(" - Not a valid interrupt pin!");
}
} else {
if ( SERIAL_CONNECTED ) {
Serial.print("ENCODER_CLK: ");
Serial.print(ENCODER_CLK);
Serial.println(" - Valid interrupt pin.");
}
//attachInterrupt(digitalPinToInterrupt(ENCODER_CLK), readEncoder, FALLING);
//attachInterrupt(digitalPinToInterrupt(ENCODER_CLK), readEncoder, CHANGE);
}
// ***********************************
if (digitalPinToInterrupt(ENCODER_BTN) == -1) {
if ( SERIAL_CONNECTED ) {
Serial.print("ENCODER_BTN: ");
Serial.print(ENCODER_BTN);
Serial.println(" - Not a valid interrupt pin!");
}
} else {
if ( SERIAL_CONNECTED ) {
Serial.print("ENCODER_BTN: ");
Serial.print(ENCODER_BTN);
Serial.println(" - Valid interrupt pin.");
}
//attachInterrupt(digitalPinToInterrupt(ENCODER_BTN), UpdateButtonPressed, FALLING);
//attachInterrupt(digitalPinToInterrupt(ENCODER_BTN), UpdateButtonUnPressed, RISING);
//attachInterrupt(digitalPinToInterrupt(ENCODER_BTN), UpdateButtonChanged, CHANGE);
}
*/
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_7x14B_tf);
tmptxt = "Booting...";
u8g2.drawStr(aligncenter(SCREEN_WIDTH / 2, tmptxt), 10, tmptxt.c_str());
u8g2.setFont(u8g2_font_6x10_tf);
tmptxt = "completed.";
u8g2.drawStr(aligncenter(SCREEN_WIDTH / 2, tmptxt), 30, tmptxt.c_str());
u8g2.sendBuffer();
delay(2000);
// ***********************************
// * rotaryEncoder INITIALIZATION
// ***********************************
rotaryEncoderAi.begin();
rotaryEncoderAi.setup(readEncoderISR);
rotaryEncoderAi.setBoundaries(minPos, maxPos, circleValues); //minValue, maxValue, circleValues true|false (when max go to min and vice versa)
rotaryEncoderAi.disableAcceleration(); //acceleration is now enabled by default - disable if you dont need it
rotaryEncoderAi.setEncoderValue(minPos);
// ***********************************
// * LOAD MAIN MENU
// ***********************************
mainMenu();
}
/************************************************************************
MAIN LOOP
************************************************************************/
void loop() {
curr_millis = millis();
blink();
UpdateButton();
if (rotaryButton.ButtonPressed) {
switch (currMenu) {
case 0:
/*****************************************************************
* Main Menu - Actions
*****************************************************************/
switch (rotaryEncoderPos.Pos)
{
case 1:
/*************************************************************
* Go To -> Cocktails Menu
*************************************************************/
unpressButton();
rotaryEncoderPos.LastPos = rotaryEncoderPos.Pos;
lastMenu = currMenu;
if ( menuItems[rotaryEncoderPos.Pos] == "Zutaten" ) {
currMenu = 3;
} else {
currMenu = 1;
}
if ( lastMenu != currMenu ) {
rotaryEncoderPos.Pos = 1;
rotaryEncoderAi.setEncoderValue(rotaryEncoderPos.Pos);
}
break;
case 2:
/*************************************************************
* Go To -> Setup Menu
*************************************************************/
unpressButton();
rotaryEncoderPos.LastPos = rotaryEncoderPos.Pos;
lastMenu = currMenu;
currMenu = 2;
if ( lastMenu != currMenu ) {
rotaryEncoderPos.Pos = 1;
rotaryEncoderAi.setEncoderValue(rotaryEncoderPos.Pos);
}
break;
default:
/*************************************************************
* Main Menus -> Do Nothing
*************************************************************/
unpressButton();
rotaryEncoderPos.LastPos = rotaryEncoderPos.Pos;
break;
}
break;
case 1:
/*****************************************************************
* Cocktails Menu - Actions
*****************************************************************/
if ( menuItems[rotaryEncoderPos.Pos] == "zur\374ck" ) {
/*************************************************************
* Go Back To -> Main Menu
*************************************************************/
unpressButton();
rotaryEncoderPos.LastPos = rotaryEncoderPos.Pos;
lastMenu = currMenu;
currMenu = 0;
if ( lastMenu != currMenu ) {
rotaryEncoderPos.Pos = 1;
rotaryEncoderAi.setEncoderValue(rotaryEncoderPos.Pos);
}
} else {
/*************************************************************
* Pour Cocktail
*************************************************************/
unpressButton();
rotaryEncoderPos.LastPos = rotaryEncoderPos.Pos;
pourCocktail( getCockailIDbyName(menuItems[rotaryEncoderPos.Pos]) );
}
break;
case 2:
/*****************************************************************
* Setup Menu - Actions
*****************************************************************/
switch (rotaryEncoderPos.Pos)
{
case 1:
/*************************************************************
* Change Ingredient
*************************************************************/
unpressButton();
rotaryEncoderPos.LastPos = rotaryEncoderPos.Pos;
lastMenu = currMenu;
currMenu = 3;
if ( lastMenu != currMenu ) {
rotaryEncoderPos.Pos = 1;
rotaryEncoderAi.setEncoderValue(rotaryEncoderPos.Pos);
}
break;
case 2:
/*************************************************************
* Calibrate Load Cell
*************************************************************/
unpressButton();
rotaryEncoderPos.LastPos = rotaryEncoderPos.Pos;
calibrateLoadCell();
break;
case 3:
/*************************************************************
* Show Load Cell Value
*************************************************************/
unpressButton();
rotaryEncoderPos.LastPos = rotaryEncoderPos.Pos;
showLoadCellValue();
break;
case 4:
/*************************************************************
* Tara LoadCell
*************************************************************/
unpressButton();
rotaryEncoderPos.LastPos = rotaryEncoderPos.Pos;
TaraLoadCell();
break;
default:
/*************************************************************
* Go Back To -> Main Menu
*************************************************************/
unpressButton();
rotaryEncoderPos.LastPos = rotaryEncoderPos.Pos;
lastMenu = currMenu;
currMenu = 0;
if ( lastMenu != currMenu ) {
rotaryEncoderPos.Pos = 1;
rotaryEncoderAi.setEncoderValue(rotaryEncoderPos.Pos);
}
break;
}
break;
case 3:
/*****************************************************************
* Ingredients Menu - Actions
*****************************************************************/
if ( menuItems[rotaryEncoderPos.Pos] == "zur\374ck" ) {
/*************************************************************
* Go Back To -> Main Menu
*************************************************************/
unpressButton();
rotaryEncoderPos.LastPos = rotaryEncoderPos.Pos;
currMenu = lastMenu;
lastMenu = 3;
if ( lastMenu != currMenu ) {
rotaryEncoderPos.Pos = 1;
rotaryEncoderAi.setEncoderValue(rotaryEncoderPos.Pos);
}
} else if ( menuItems[rotaryEncoderPos.Pos] == "reset" ) {
/*************************************************************
* Reset Ingredients & Go Back To -> Main Menu
*************************************************************/
unpressButton();
rotaryEncoderPos.LastPos = rotaryEncoderPos.Pos;
rotaryEncoderPos.Pos = 1;
rotaryEncoderAi.setEncoderValue(rotaryEncoderPos.Pos);
resetIngredient();
} else {
/*************************************************************
* Modify Ingredients
*************************************************************/
unpressButton();
rotaryEncoderPos.LastPos = rotaryEncoderPos.Pos;
modifyIngredient ( getIngredientIDbyName(menuItems[rotaryEncoderPos.Pos]) );
}
break;
}
}
if ( ((curr_millis - rotaryButton.LastButtonChange) < (loop_delay + 10)) || ((curr_millis - LastEncoderPosChange) < (loop_delay + 10))) {
updateMenu();
}
delay(loop_delay);
}
Loading
esp32-s3-devkitc-1
esp32-s3-devkitc-1