/*
#define SD_CS_PIN 34
const int HX711_dout = 3; // HX711_DT
const int HX711_sck = 4; // HX711_SCK
#define ENCODER_CLK 5
#define ENCODER_DT 6
#define ENCODER_BTN 7
#define PIN_WS2812B 2
#define NUM_PIXELS 16 // The number of LEDs (pixels) on WS2812B LED strip
const uint8_t NumPumps = 8;
const uint8_t PumpPIN[NumPumps] = {17, 16, 15, 14, 13, 12, 11, 10};
*/
/************************************************************************
* SD CARD
************************************************************************
* INCLUDES
************************************************************************/
#include <SD.h>
/************************************************************************
* PINS
************************************************************************/
#define SD_CS_PIN 34
/************************************************************************/
/************************************************************************
* OLED DISPLAY
************************************************************************
* INCLUDES
************************************************************************/
#include <Wire.h>
#include <Adafruit_GFX.h> // Make sure Adafruit libs for the OLED are installed
#include <Adafruit_SSD1306.h>
/************************************************************************
* PINS
************************************************************************/
// SDA ( 8 ) -> SDA
// SCL ( 9 ) -> SCL
/************************************************************************/
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
/************************************************************************
* constructor:
* oled SSD1306 display connected to I2C
************************************************************************/
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
/************************************************************************/
/************************************************************************
* LOAD CELL
************************************************************************
* INCLUDES
************************************************************************/
#include <HX711_ADC.h>
#if defined(ESP8266)|| defined(ESP32) || defined(AVR)
#include <EEPROM.h>
#endif
/************************************************************************
* PINS
************************************************************************/
const int HX711_dout = 3; // 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
************************************************************************
* PINS:
************************************************************************/
#define ENCODER_CLK 5
#define ENCODER_DT 6
#define ENCODER_BTN 7
/************************************************************************
* STRUCT:
************************************************************************/
struct rotaryEncoders {
uint8_t Pos = 1; // current value selected with rotary encoder (updated by interrupt routine
uint8_t PosDir = 0;
uint8_t LastPos = Pos; // lastPosition
uint8_t MainMenuPos = Pos;
uint16_t value = 0;
bool locked = false;
bool ButtonPressed = false;
bool ButtonPressedLong = false;
bool prevButtonPressed = false; // used to debounce button
uint32_t LastPosChange = 0; // last time state of button changed (for debouncing)
uint32_t LastButtonChange = 0; // last time state of button changed (for debouncing)
bool ButtonPressedFixed = 0; // flag set when the button is pressed (it has to be manually reset)
};
/************************************************************************/
rotaryEncoders rotaryEncoder;
/************************************************************************
* SOME VARIBLES:
************************************************************************/
uint8_t rotaryEncoderSteps = 15;
/************************************************************************/
/************************************************************************
* MENU THINGS
************************************************************************/
String menuItems[99];
uint8_t minPos = 1;
uint8_t maxPos = 10;
uint8_t menuPos = 0;
uint8_t currMenu = 0;
uint8_t lastMenu = 0;
uint8_t rotaryEncoderMaxValue = 10;
uint8_t rotaryEncoderMinValue = 0;
uint32_t curr_millis;
uint16_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 2
#define NUM_PIXELS 16 // 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] = {17, 16, 15, 14, 13, 12, 11, 10};
/* Setting PWM Properties */
const int PWMFreq = 18000; /* 18 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;
/************************************************************************/
/************************************************************************/
/************************************************************************/
/************************************************************************/
bool SERIAL_CONNECTED = false;
/************************************************************************
* SETUP LOOP
************************************************************************/
void setup() {
// ***********************************
// * Serial Interface INITIALIZATION
// ***********************************
Serial.begin(57600);
delay(100);
// ***********************************
int i = 0;
while(!Serial.available()) {
delay(10);
i++;
if ( i >= 100 ) {
break;
}
}
// ***********************************
if (Serial.available()) {
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);
// ***********************************
// * Pumps
// ***********************************
ledcSetup(0, PWMFreq, PWMResolution);
for ( int i = 0; i < NumPumps; i++) {
pinMode(PumpPIN[i], OUTPUT);
digitalWrite(PumpPIN[i], LOW);
ledcSetup(0, PWMFreq, PWMResolution);
}
// ***********************************
// * configure gpio pins for rotary encoder
// ***********************************
pinMode(ENCODER_CLK, INPUT);
pinMode(ENCODER_DT, INPUT);
pinMode(ENCODER_BTN, INPUT_PULLUP);
// ***********************************
// * OLED DISPLAY INITIALIZATION
// ***********************************
if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
if ( SERIAL_CONNECTED ) {
Serial.println(F("SSD1306 allocation failed"));
}
for (;;); // Don't proceed, loop forever
} else {
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0,0);
display.println("Booting...");
display.display();
}
// ***********************************
// * SD CARD INITIALIZATION
// ***********************************
if (!SD.begin(SD_CS_PIN)) {
if ( SERIAL_CONNECTED ) Serial.println("SD Card initialization failed!");
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0,0);
display.println("Booting...");
display.setTextSize(1);
display.println("");
display.println("SD Card initialization failed!");
while (true);
}
if ( SERIAL_CONNECTED ) {
Serial.println("SD Card initialization done.");
}
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0,0);
display.println("Booting...");
display.setTextSize(1);
display.println("");
display.println("SD Card initialization done.");
display.display();
// ***********************************
// * 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");
}
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0,0);
display.println("Booting...");
display.setTextSize(1);
display.println("");
display.println("Timeout, check MCU>HX711 wiring and pin designations");
display.display();
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)
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 > 5) {
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");
}
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0,0);
display.println("Booting...");
display.setTextSize(1);
display.println("");
display.println("HX711 initialization done");
display.display();
while (!LoadCell.update());
}
// ***********************************
// * READ INGREDIENTS
// ***********************************
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0,0);
display.println("Booting...");
display.setTextSize(1);
display.println("");
display.println("loading Ingredients...");
display.display();
readIngredients();
/*
readIngredients2();
delay(1000);
writeIngredients();
NumIngredients=0;
delay(1000);
readIngredients2();
for (;;); // Don't proceed, loop forever
*/
// ***********************************
// * CHECK INGREDIENTS
// ***********************************
if (!checkIngredient()) {
if ( SERIAL_CONNECTED ) Serial.println("something went wrong");
}
// ***********************************
// * READ COCKTAILS
// ***********************************
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0,0);
display.println("Booting...");
display.setTextSize(1);
display.println("");
display.println("loading Cocktails...");
display.display();
readCocktails();
// ***********************************
// * 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);
}
// ***********************************
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);
}
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0,0);
display.println("Booting...");
display.setTextSize(1);
display.println("");
display.println("completed.");
display.display();
delay(2500);
// ***********************************
// * LOAD MAIN MENU
// ***********************************
mainMenu();
}
/************************************************************************
* MAIN LOOP
************************************************************************/
void loop() {
curr_millis = millis();
blink();
// ws2812b.show();
UpdateButton();
if (rotaryEncoder.ButtonPressedFixed) {
switch (currMenu) {
case 0: // Main Menu - Actions
switch (rotaryEncoder.Pos)
{
case 1: // Go To -> Cocktails Menu
unpressButton();
rotaryEncoder.LastPos = rotaryEncoder.Pos;
lastMenu = currMenu;
if ( menuItems[rotaryEncoder.Pos] == "Zutaten" ) {
currMenu = 3;
} else {
currMenu = 1;
}
if ( lastMenu != currMenu ) rotaryEncoder.Pos = 1;
break;
case 2: // Go To -> Setup Menu
unpressButton();
rotaryEncoder.LastPos = rotaryEncoder.Pos;
lastMenu = currMenu;
currMenu = 2;
if ( lastMenu != currMenu ) rotaryEncoder.Pos = 1;
break;
default: // Main Menus -> Do Nothing
unpressButton();
rotaryEncoder.LastPos = rotaryEncoder.Pos;
break;
}
break;
case 1: // Cocktails Menu - Actions
if ( menuItems[rotaryEncoder.Pos] == "zurueck" ) {
// Go Back To -> Main Menu
unpressButton();
rotaryEncoder.LastPos = rotaryEncoder.Pos;
lastMenu = currMenu;
currMenu = 0;
if ( lastMenu != currMenu ) rotaryEncoder.Pos = 1;
} else {
unpressButton();
rotaryEncoder.LastPos = rotaryEncoder.Pos;
pourCocktail( getCockailIDbyName(menuItems[rotaryEncoder.Pos]) );
}
break;
case 2: // Setup Menu - Actions
switch (rotaryEncoder.Pos)
{
case 1: // Waage
unpressButton();
rotaryEncoder.LastPos = rotaryEncoder.Pos;
showLoadCellValue();
break;
case 2: // Tara
unpressButton();
rotaryEncoder.LastPos = rotaryEncoder.Pos;
TaraLoadCell();
break;
case 3: // Calibrate Load Cell
unpressButton();
rotaryEncoder.LastPos = rotaryEncoder.Pos;
calibrateLoadCell();
break;
case 4: // Change Ingredient
unpressButton();
rotaryEncoder.LastPos = rotaryEncoder.Pos;
lastMenu = currMenu;
currMenu = 3;
if ( lastMenu != currMenu ) rotaryEncoder.Pos = 1;
break;
default: // Go Back To -> Main Menu
// Go Back To -> Main Menu
unpressButton();
rotaryEncoder.LastPos = rotaryEncoder.Pos;
lastMenu = currMenu;
currMenu = 0;
if ( lastMenu != currMenu ) rotaryEncoder.Pos = 1;
break;
}
break;
case 3: // Zutaten Menu - Actions
if ( menuItems[rotaryEncoder.Pos] == "zurueck" ) {
// Go Back To -> Main Menu
unpressButton();
rotaryEncoder.LastPos = rotaryEncoder.Pos;
currMenu = lastMenu;
lastMenu = 3;
if ( lastMenu != currMenu ) rotaryEncoder.Pos = 1;
} else if ( menuItems[rotaryEncoder.Pos] == "reset" ) {
// Go Back To -> Main Menu
unpressButton();
rotaryEncoder.LastPos = rotaryEncoder.Pos;
rotaryEncoder.Pos = 1;
resetIngredient();
} else {
unpressButton();
rotaryEncoder.LastPos = rotaryEncoder.Pos;
modifiyIngredient ( getIngredientIDbyName(menuItems[rotaryEncoder.Pos]) );
}
break;
}
}
if ( ((curr_millis - rotaryEncoder.LastButtonChange) < (loop_delay+10)) || ((curr_millis - rotaryEncoder.LastPosChange) < (loop_delay+10))) {
updateMenu();
}
delay(loop_delay);
}
/************************************************************************
* 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++ ){
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++ ){
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 - 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;
uint8_t mi = 0;
//String menuItems[maxPos+1];
menuItems[mi] = "Main Menu";
mi++;
if (NumCocktailsAvailable>0) {
menuItems[mi] = "Cocktails";
mi++;
} else {
menuItems[mi] = "Zutaten";
mi++;
}
menuItems[mi] = "Setup";
display.clearDisplay();
display.setCursor(0,0);
display.setTextSize(2);
display.println(menuItems[0]);
display.setTextSize(2);
display.setTextColor(SSD1306_WHITE, SSD1306_BLACK);
if ( rotaryEncoder.Pos == 1 ) {
display.println("");
} else {
display.println(menuItems[rotaryEncoder.Pos-1]);
}
display.setTextColor(SSD1306_BLACK, SSD1306_WHITE);
display.println(menuItems[rotaryEncoder.Pos]);
display.setTextColor(SSD1306_WHITE, SSD1306_BLACK);
if ( rotaryEncoder.Pos == maxPos ) {
display.println("");
} else {
display.println(menuItems[rotaryEncoder.Pos+1]);
}
display.display();
}
/************************************************************************
* COCKTAIL MENU
************************************************************************/
void CocktailMenu() {
maxPos = NumCocktailsAvailable+1;
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] = "zurueck";
display.clearDisplay();
display.setCursor(0,0);
display.setTextSize(2);
display.println(menuItems[0]);
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE, SSD1306_BLACK);
if ( rotaryEncoder.Pos == 1 ) {
display.println("");
} else {
display.println(menuItems[rotaryEncoder.Pos-1]);
}
display.setTextColor(SSD1306_BLACK, SSD1306_WHITE);
display.println(menuItems[rotaryEncoder.Pos]);
display.setTextColor(SSD1306_WHITE, SSD1306_BLACK);
if ( rotaryEncoder.Pos == maxPos ) {
display.println("");
} else {
display.println(menuItems[rotaryEncoder.Pos+1]);
}
display.display();
}
/************************************************************************
* Zutaten MENU
************************************************************************/
void ZutatenMenu() {
maxPos = NumIngredients+2;
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] = "zurueck";
display.clearDisplay();
display.setCursor(0,0);
display.setTextSize(2);
display.println(menuItems[0]);
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE, SSD1306_BLACK);
if ( rotaryEncoder.Pos <= 2 ) {
display.println("");
} else {
display.println(menuItems[rotaryEncoder.Pos-2]);
}
if ( rotaryEncoder.Pos == 1 ) {
display.println("");
} else {
display.println(menuItems[rotaryEncoder.Pos-1]);
}
display.setTextColor(SSD1306_BLACK, SSD1306_WHITE);
display.println(menuItems[rotaryEncoder.Pos]);
display.setTextColor(SSD1306_WHITE, SSD1306_BLACK);
if ( rotaryEncoder.Pos == maxPos ) {
display.println("");
} else {
display.println(menuItems[rotaryEncoder.Pos+1]);
}
if ( rotaryEncoder.Pos >= maxPos-1 ) {
display.println("");
} else {
display.println(menuItems[rotaryEncoder.Pos+2]);
}
display.display();
}
/************************************************************************
* Setup MENU
************************************************************************/
void SetupMenu() {
maxPos = 5;
//String menuItems[maxPos+1];
menuItems[0] = "Setup Menu";
menuItems[1] = "Waage";
menuItems[2] = "Tara";
menuItems[3] = "Calibrate";
menuItems[4] = "Zutaten";
menuItems[5] = "zurueck";
display.clearDisplay();
display.setCursor(0,0);
display.setTextSize(2);
display.println(menuItems[0]);
display.setTextSize(2);
display.setTextColor(SSD1306_WHITE, SSD1306_BLACK);
if ( rotaryEncoder.Pos == 1 ) {
display.println("");
} else {
display.println(menuItems[rotaryEncoder.Pos-1]);
}
display.setTextColor(SSD1306_BLACK, SSD1306_WHITE);
display.println(menuItems[rotaryEncoder.Pos]);
display.setTextColor(SSD1306_WHITE, SSD1306_BLACK);
if ( rotaryEncoder.Pos == maxPos ) {
display.println("");
} else {
display.println(menuItems[rotaryEncoder.Pos+1]);
}
display.display();
}
/************************************************************************
* 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();
/*
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0,0);
display.println("1");
display.println("2");
display.println("3");
display.println("4");
display.println("5");
display.println("6");
display.println("7");
display.println("8");
display.display();
*/
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0,0);
display.println(Cocktail[CocktailID].CocktailName);
display.println("wird zubereitet.");
display.println();
display.println();
display.println("Bitte Glas platzieren");
display.println();
display.println();
display.println("Bitte warten...");
display.display();
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 ) {
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 (rotaryEncoder.ButtonPressedFixed == false) {
curr_millis = millis();
blink();
UpdateButton();
display.clearDisplay();
display.setCursor(0,0);
display.println(Cocktail[CocktailID].CocktailName);
display.println("wird zubereitet.");
display.println();
display.println();
display.println("Bitte Glas platzieren");
display.println();
display.println();
display.println("Click to continue.");
display.display();
}
unpressButton();
}
display.clearDisplay();
display.setCursor(0,0);
display.println(Cocktail[CocktailID].CocktailName);
display.println("wird zubereitet.");
display.println();
display.println();
display.println("Waage tarieren");
display.println();
display.println();
display.println("Bitte warten...");
display.display();
TaraLoadCellnoFeedback();
//getChilledLoadCellValue();
for (int var = 0; var < NumPumps; var++) {
if (Cocktail[CocktailID].IngredientAmount[var] && Cocktail[CocktailID].IngredientName[var] != "") {
display.clearDisplay();
display.setCursor(0,0);
display.println(Cocktail[CocktailID].CocktailName);
display.println("wird zubereitet.");
display.println();
display.println();
display.print(Cocktail[CocktailID].IngredientAmount[var]);
display.print("ml ");
display.println(Cocktail[CocktailID].IngredientName[var]);
display.println();
display.println();
display.println("Bitte warten...");
display.display();
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);
}
display.clearDisplay();
display.setCursor(0,0);
display.println();
display.println();
display.println(Cocktail[CocktailID].CocktailName);
display.println();
display.println("ist fertig.");
display.println();
display.println("Bitte entnehmen.");
display.println();
display.display();
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
************************************************************************/
/*
@brief Set text 'magnification' size. Each increase in s makes 1 pixel
that much bigger.
@param s Desired text size. 1 is default 6x8, 2 is 12x16, 3 is 18x24, etc
*/
/************************************************************************
* 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;
}
display.fillRect(110-24, 48, 5*6, 8,0);
display.display();
display.setCursor(xpos,48);
display.print(poured);
display.setCursor(116,48);
display.print("ml");
display.display();
}
//void ControlPWM_SINGLE(uint8_t nr, uint8_t start, uint8_t ende, bool soft);
ControlPWM_SINGLE(PumpID-1, 100, 0, false);
delay(1000);
}
void ControlPWM_CHANNEL(uint8_t channel, uint8_t speed) {
int dutyCycle = map(speed, 0, 100, 0, MAX_DUTY_CYCLE);
if ( SERIAL_CONNECTED ) {
Serial.print("Setting LED Channel ");
Serial.print(channel);
Serial.print(" PWM to: ");
Serial.print(speed);
Serial.print("% - dutyCycle: ");
Serial.println(dutyCycle);
}
ledcWrite(channel, dutyCycle);
}
void ControlPWM_SINGLE(uint8_t nr, uint8_t start, uint8_t ende, bool soft) {
ledcAttachPin(PumpPIN[nr], 0);
if ( soft ) {
if ( start < ende ) {
for(int value = 0; value <= 100; value++) {
ControlPWMChannel(0, value);
delay(10);
}
} else {
for(int value = 100; value >= 0; value--) {
ControlPWMChannel(0, value);
delay(10);
}
}
}
ledcDetachPin(PumpPIN[nr]);
if ( ende == 0 ) {
digitalWrite(PumpPIN[nr], LOW);
} else if ( ende == 100 ) {
digitalWrite(PumpPIN[nr], HIGH);
}
}
void ControlPWMChannel(uint8_t channel, uint8_t value) {
int dutyCycle = map(value, 0, 100, 0, MAX_DUTY_CYCLE);
ledcWrite(channel, 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
************************************************************************/
// 1 is 6x8, 2 is 12x16, 3 is 18x24, etc
void modifiyIngredient(uint8_t IngredientID) {
unpressButton();
//Serial.println(Ingredient[IngredientID].IngredientName);
maxPos = 2;
bool modify = false;
float old_steps = rotaryEncoderSteps;
rotaryEncoder.Pos = 1;
bool _resume = false;
int old_value = Ingredient[IngredientID].PumpID;
while ( !_resume ) {
UpdateButton();
if ( rotaryEncoder.Pos == 1 && rotaryEncoder.ButtonPressedFixed && !modify ) {
unpressButton();
rotaryEncoder.locked = true;
rotaryEncoderSteps = 1;
modify = true;
rotaryEncoderMinValue = 0;
rotaryEncoderMaxValue = NumPumps;
rotaryEncoder.value = Ingredient[IngredientID].PumpID;
}
if ( rotaryEncoder.Pos == 1 && rotaryEncoder.ButtonPressedFixed && modify) {
unpressButton();
rotaryEncoder.locked = false;
rotaryEncoderSteps = old_steps;
modify = false;
Ingredient[IngredientID].PumpID = rotaryEncoder.value;
/*
Serial.print("Old Value:");
Serial.println(old_value);
Serial.print("New Value:");
Serial.print(Ingredient[IngredientID].PumpID);
*/
if ( !checkIngredient() ) {
Ingredient[IngredientID].PumpID = old_value;
}
/*
Serial.print("Applied Value:");
Serial.println(Ingredient[IngredientID].PumpID);
*/
}
if ( rotaryEncoder.Pos == 2 && rotaryEncoder.ButtonPressedFixed ) {
unpressButton();
_resume = true;
}
if ( ((curr_millis - rotaryEncoder.LastButtonChange) < 60) || ((curr_millis - rotaryEncoder.LastPosChange) < 60)) {
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
display.setTextSize(2);
display.setCursor(0,0);
display.print(Ingredient[IngredientID].IngredientName);
display.setCursor(0,32);
if ( rotaryEncoder.Pos == 1 && !modify ) {
display.setTextColor(SSD1306_BLACK, SSD1306_WHITE);
} else {
display.setTextColor(SSD1306_WHITE, SSD1306_BLACK);
}
display.print("Pumpe");
display.setTextColor(SSD1306_WHITE, SSD1306_BLACK);
display.print(": ");
display.setCursor(96,32);
if (modify) {
display.setTextColor(SSD1306_BLACK, SSD1306_WHITE);
display.print(int(rotaryEncoder.value));
display.setTextColor(SSD1306_WHITE, SSD1306_BLACK);
} else {
display.print(Ingredient[IngredientID].PumpID);
}
display.setTextSize(1);
display.setCursor(0,48);
if (Ingredient[IngredientID].alcoholic) {
display.print("Alkohol");
}
display.setCursor(86,56);
if ( rotaryEncoder.Pos == 2 ) {
display.setTextColor(SSD1306_BLACK, SSD1306_WHITE);
} else {
display.setTextColor(SSD1306_WHITE, SSD1306_BLACK);
}
display.print("zurueck");
display.display();
}
}
display.setTextColor(SSD1306_WHITE, SSD1306_BLACK);
checkCocktails();
}
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;
}
}
}
void resetIngredient() {
for (int i = 0; i < NumIngredients; i++) {
Ingredient[i].PumpID = 0;
}
checkCocktails();
}
/************************************************************************
* START - ROTARY ENCODER CODE BASE
************************************************************************
* READ ENCODER
************************************************************************/
void readEncoder() {
int dtValue = digitalRead(ENCODER_DT);
rotaryEncoder.LastPosChange = curr_millis;
if (dtValue == HIGH) {
rotaryEncoder.PosDir = 1;
if (!rotaryEncoder.locked) {
if ( rotaryEncoder.Pos < maxPos ) rotaryEncoder.Pos++;
}
if ( rotaryEncoder.value < rotaryEncoderMaxValue ) rotaryEncoder.value = rotaryEncoder.value + rotaryEncoderSteps;
}
if (dtValue == LOW) {
rotaryEncoder.PosDir = 2;
if (!rotaryEncoder.locked) {
if ( rotaryEncoder.Pos > minPos ) rotaryEncoder.Pos--;
}
if ( rotaryEncoder.value > rotaryEncoderMinValue ) rotaryEncoder.value = rotaryEncoder.value - rotaryEncoderSteps;
}
//SerialDebug(0);
}
/************************************************************************
* UpdateButton
************************************************************************/
void UpdateButton() {
rotaryEncoder.ButtonPressed = !digitalRead(ENCODER_BTN);
if ( rotaryEncoder.ButtonPressed != rotaryEncoder.prevButtonPressed ) {
if ( !rotaryEncoder.ButtonPressed && rotaryEncoder.prevButtonPressed ) {
rotaryEncoder.ButtonPressedFixed = true;
if ( ((curr_millis - rotaryEncoder.LastButtonChange) > 1000) ) {
rotaryEncoder.ButtonPressedLong = true;
} else {
rotaryEncoder.ButtonPressedLong = false;
}
SerialDebug(rotaryEncoder.ButtonPressed);
}
rotaryEncoder.prevButtonPressed = rotaryEncoder.ButtonPressed;
rotaryEncoder.LastButtonChange = curr_millis;
//SerialDebug(rotaryEncoder.ButtonPressed);
}
}
/************************************************************************
* unpressButton
************************************************************************/
void unpressButton() {
rotaryEncoder.ButtonPressedFixed = false;
if (rotaryEncoder.ButtonPressedLong == true ) rotaryEncoder.ButtonPressedLong = false;
rotaryEncoder.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(rotaryEncoder.ButtonPressed);
Serial.print(" - prevButtonPressed: ");
Serial.print(rotaryEncoder.prevButtonPressed);
Serial.print(" - LastButtonChange: ");
Serial.print(rotaryEncoder.LastButtonChange);
Serial.print(" - ButtonPressedFixed: ");
Serial.print(rotaryEncoder.ButtonPressedFixed);
if (rotaryEncoder.ButtonPressedLong) {
Serial.print(" (long)");
} else {
Serial.print(" (short)");
}
Serial.print(" - Pos: ");
Serial.print(rotaryEncoder.Pos);
if (rotaryEncoder.PosDir == 1) {
Serial.print(" - Rotated clockwise ⏩");
} else if (rotaryEncoder.PosDir == 2) {
Serial.print(" - Rotated counterclockwise ⏪");
}
Serial.println();
}
}
/************************************************************************
* END - ROTARY ENCODER CODE BASE
************************************************************************/
/************************************************************************
* START - ROTARY ENCODER CODE BASE (TEST)
************************************************************************/
/*
void UpdateButtonChanged() {
bool ButtonPressed = !digitalRead(ENCODER_BTN); // read current button state
if ( digitalRead(ENCODER_BTN) == LOW ) {
rotaryEncoder.prevButtonPressed = false;
rotaryEncoder.ButtonPressed = true;
SerialDebug(2);
rotaryEncoder.LastButtonChange = curr_millis;
} else {
if ( rotaryEncoder.ButtonPressed ) {
if ((curr_millis - rotaryEncoder.LastButtonChange) > 1000) {
rotaryEncoder.ButtonPressedLong = !rotaryEncoder.ButtonPressedLong;
}
} else {
rotaryEncoder.ButtonPressedFixed = true;
}
rotaryEncoder.prevButtonPressed = true;
rotaryEncoder.ButtonPressed = false;
SerialDebug(3);
rotaryEncoder.LastButtonChange = curr_millis;
}
}
void UpdateButtonPressed() {
detachInterrupt(digitalPinToInterrupt(ENCODER_BTN));
rotaryEncoder.prevButtonPressed = false;
rotaryEncoder.ButtonPressed = true;
SerialDebug(2);
rotaryEncoder.LastButtonChange = curr_millis;
attachInterrupt(digitalPinToInterrupt(ENCODER_BTN), UpdateButtonUnPressed, RISING);
}
void UpdateButtonUnPressed() {
detachInterrupt(digitalPinToInterrupt(ENCODER_BTN));
if ( rotaryEncoder.ButtonPressed ) {
if ((curr_millis - rotaryEncoder.LastButtonChange) > 1000) {
rotaryEncoder.ButtonPressedLong = !rotaryEncoder.ButtonPressedLong;
}
} else {
rotaryEncoder.ButtonPressedFixed = true;
}
rotaryEncoder.prevButtonPressed = true;
rotaryEncoder.ButtonPressed = false;
SerialDebug(3);
rotaryEncoder.LastButtonChange = curr_millis;
attachInterrupt(digitalPinToInterrupt(ENCODER_BTN), UpdateButtonPressed, FALLING);
}
*/
/************************************************************************
* END - ROTARY ENCODER CODE BASE (TEST)
************************************************************************/
/************************************************************************
* START - LOAD CELL CODE BASE
************************************************************************/
/************************************************************************
* showLoadCellValue
************************************************************************/
void showLoadCellValue() {
static boolean newDataReady = 0;
while (rotaryEncoder.ButtonPressedFixed == false) {
curr_millis = millis();
blink();
UpdateButton();
if (LoadCell.update()) newDataReady = true;
if (newDataReady) {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0,0);
display.println("Weight:");
display.println(LoadCell.getData());
display.display();
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() {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0,0);
display.println("Starting Tara.");
display.display();
boolean _resume = false;
while (_resume == false) {
curr_millis = millis();
blink();
LoadCell.update();
UpdateButton();
if ( rotaryEncoder.ButtonPressedFixed ) {
unpressButton();
display.clearDisplay();
display.setCursor(0,0);
display.setTextSize(2);
display.println("please wait...");
display.display();
LoadCell.tareNoDelay();
}
if (LoadCell.getTareStatus() == true) {
display.clearDisplay();
display.setCursor(0,0);
display.setTextSize(2);
display.println("Tare complete");
display.display();
delay(500);
_resume = true;
}
}
}
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() {
rotaryEncoder.LastPos = rotaryEncoder.Pos;
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0,0);
display.println("Start calibration:");
display.println("Remove any load applied to the load cell.");
display.display();
rotaryEncoder.value = 50;
rotaryEncoderSteps = 10;
rotaryEncoderMaxValue = 5000;
boolean _resume = false;
while (_resume == false) {
curr_millis = millis();
blink();
LoadCell.update();
UpdateButton();
if ( rotaryEncoder.ButtonPressedFixed ) {
if (rotaryEncoder.ButtonPressedLong) {
unpressButton();
return;
} else {
unpressButton();
display.clearDisplay();
display.setCursor(0,0);
display.setTextSize(1);
display.println("please wait...");
display.display();
LoadCell.tareNoDelay();
}
}
if (LoadCell.getTareStatus() == true) {
display.clearDisplay();
display.setCursor(0,0);
display.setTextSize(1);
display.println("Tare complete");
display.display();
delay(1000);
_resume = true;
}
}
int known_mass = 0;
_resume = false;
while (_resume == false) {
curr_millis = millis();
blink();
UpdateButton();
LoadCell.update();
display.clearDisplay();
display.setCursor(0,0);
display.setTextSize(1);
display.println("Now, place your known mass.");
display.println();
display.print(rotaryEncoder.value);
display.print("g");
display.display();
if ( rotaryEncoder.ButtonPressedFixed ) {
known_mass = rotaryEncoder.value;
unpressButton();
_resume = true;
}
}
display.clearDisplay();
display.setCursor(0,0);
display.setTextSize(1);
display.println("Your known mass:");
display.print(known_mass);
display.println("g");
display.display();
delay(1000);
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
display.clearDisplay();
display.setCursor(0,0);
display.setTextSize(1);
display.print("New calibration value has been saved and set to: ");
display.print(newCalibrationValue);
display.display();
delay(1000);
#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);
display.clearDisplay();
display.setCursor(0,0);
display.setTextSize(1);
display.print("Value: ");
display.println(newCalibrationValue);
display.print(" saved to EEPROM address: ");
display.println(calVal_eepromAdress);
display.display();
delay(1000);
rotaryEncoder.Pos = rotaryEncoder.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
************************************************************************/
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' || c == '\n') { // NEW LINE
if ( str.toInt() == 0 ) {
Ingredient[line-1].alcoholic = false;
} else {
Ingredient[line-1].alcoholic = true;
}
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!");
}
int i = 0;
while ( DefaultIngredient[i].IngredientName ) {
Ingredient[i].PumpID = DefaultIngredient[i].PumpID;
Ingredient[i].IngredientName = DefaultIngredient[i].IngredientName;
Ingredient[i].alcoholic = DefaultIngredient[i].alcoholic;
i++;
}
NumIngredients = i-1;
}
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 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' || 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 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]);
}
}
}
}
}
}
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 writeIngredients() {
if ( SD.exists("/Ingredients2.csv") ) {
if ( SERIAL_CONNECTED ) {
Serial.println("Deleting... Ingredients2.csv");
}
SD.remove("/Ingredients2.csv");
if ( SD.exists("/Ingredients2.csv") ) {
Serial.println("deleted");
} else {
Serial.println("not deleted");
}
} else {
Serial.println("file does not exsits.");
}
File myFile = SD.open("/Ingredients2.csv", FILE_WRITE);
if ( SD.exists("/Ingredients2.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");
}
String str = "";
for (int i = 0; i < NumIngredients; i++) {
str = String(Ingredient[i].PumpID) + "," + Ingredient[i].IngredientName + ",";
//myFile.print(String(Ingredient[i].PumpID));
//myFile.print(",");
//myFile.print(Ingredient[i].IngredientName);
//myFile.print(",");
if (Ingredient[i].alcoholic) {
//myFile.print("1");
str = str + "1";
} else {
//myFile.print("0");
str = str + "0";
}
myFile.println(str);
if ( SERIAL_CONNECTED ) {
Serial.print(i);
Serial.print(" - STRING: ");
Serial.println(str);
/*
Serial.print("VALUES: ");
Serial.print(Ingredient[i].PumpID);
Serial.print(",");
Serial.print(Ingredient[i].IngredientName);
Serial.print(",");
Serial.println(Ingredient[i].alcoholic);
*/
}
myFile.flush();
}
Serial.print("Size: ");
Serial.println(myFile.size());
myFile.close();
} else {
if ( SERIAL_CONNECTED ) {
Serial.println("Can't write to file.");
}
}
// Example of reading file from the card:
File textFile = SD.open("/Ingredients2.csv");
if (textFile) {
Serial.print("Ingredients2.csv: ");
while (textFile.available()) {
Serial.write(textFile.read());
}
textFile.close();
Serial.println();
} else {
Serial.println("error opening Ingredients2.csv!");
}
}
void readIngredients2() {
File textFile = SD.open("/Ingredients2.csv");
if (textFile) {
if ( SERIAL_CONNECTED ) {
Serial.println("reading Ingredients from: Ingredients2.csv: ");
}
int line = 0;
int field = 0;
int lastfield = 0;
String str = "";
while (textFile.available()) {
char c = textFile.read();
if (c == '\r' || c == '\n') { // NEW LINE
if ( str.toInt() == 0 ) {
Ingredient[line-1].alcoholic = false;
} else {
Ingredient[line-1].alcoholic = true;
}
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 Ingredients2.csv!");
}
int i = 0;
while ( DefaultIngredient[i].IngredientName ) {
Ingredient[i].PumpID = DefaultIngredient[i].PumpID;
Ingredient[i].IngredientName = DefaultIngredient[i].IngredientName;
Ingredient[i].alcoholic = DefaultIngredient[i].alcoholic;
i++;
}
NumIngredients = i-1;
}
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("----------------------------------------");
}
}