Help With code for my bottle filler

Hi all.
I need som help with a bit of code in my bottle filler.
the code comes originaly from Kloon on github but i have change a lot of it.
in his original code he hade a #define CONTINUOUS_FILLING. By uncommit this the program goes in to a semi auto mode. what i have tried to do is have a puch button (pullup) to acitavte/diactivate this function. so is the any of you uote there that can help me with this.

#include <Wire.h>

#include <LiquidCrystal_I2C.h>


#include <TimerOne.h>

/**
 * Open Beer Filler
 * Copyright (c) 2020 Gerhard Potgieter [https://gerhardpotgieter.com]
 *
 * Based on an idea by Christopher Harrison-Hawkes [https://harrisonsbrewery.com]
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */
//#pragma once

// Library includes.
// AVR(UNO) Libraries.
#ifdef __AVR__
#include <TimerOne.h>
#endif


// Project specific includes.
/**
 * 
 */ 
 //Set the LCD address to 0x27 for a 20 chars and 4 line display
LiquidCrystal_I2C lcd(0x27, 20, 4);


/**
 * InputConfig.h Pin definitions
 */
#define START_BUTTON 8
#define BEER_INLET_SOL_1 5
#define BEER_INLET_SOL_2 6
#define BEER_INLET_SOL_3 7
#define BEER_INLET_SOL_4 9
#define BEER_FILL_SENSOR_1 A0
#define BEER_FILL_SENSOR_2 A1
#define BEER_FILL_SENSOR_3 A4
#define BEER_FILL_SENSOR_4 A3
#define BEER_FILL_SENSOR_POT A2
#define CO2_PURGE_SOL 4
#define FILL_RAIL_SOL 3
#define BEER_BELT_SOL 2
#define CAPER_SOL 10
#define AUTO_BUTTON 11
//#pragma once

/**
 * Config.h General Config Options
 */
#define CO2_PURGE_PERIOD 2000
#define MOVE_BEER_BELT_PERIOD 5000
#define FILLER_TUBE_MOVEMENT_DELAY 2000
#define CO2_PURGE_RETRACTION_DELAY 1000
#define CO2_PURGE_RETRACTION_PERIOD 500
#define FILL_SENSORS_TIMER_FREQUENCY 100000 // 100ms This value needs to be defined in microseconds.
#define FILL_SENSORS_TRIGGER 400 // Int between 0 and 1023 used to trigger the fill sensor: operating voltage(5v or 3.3v) / 1024
#define VARIABLE_FILL_SENSOR_TRIGGER true // Use a potentiometer to adjust trigger value
#define CAPER_PERIOD 5000
#define RAISING_FILLER_TUBES_DELAY 2000
/**
 * Feature flags
 */
//#define CONINUOUS_FILLING // Uncomment this to have the filling process repeat for new batch after the current batch has completed it filling.

/**
 * ***************************************************************************
 * ******************************* VARIABLES *********************************
 * ***************************************************************************
 */
volatile bool fillSensor1Triggered = false;
volatile bool fillSensor2Triggered = false;
volatile bool fillSensor3Triggered = false;
volatile bool fillSensor4Triggered = false;
bool idleMessageDisplayed = false;
enum ProgramState {UNDEF,IDLE,START,FILLING,STOP};
ProgramState currentState = UNDEF;
int sensorValue;

/**
 * ***************************************************************************
 * ******************************** FUNCTIONS ********************************
 * ***************************************************************************
 */
void setupPins() {
  // Filler solenoids.
  pinMode(BEER_INLET_SOL_1, OUTPUT);
  pinMode(BEER_INLET_SOL_2, OUTPUT);
  pinMode(BEER_INLET_SOL_3, OUTPUT);
  pinMode(BEER_INLET_SOL_4, OUTPUT);

  // CO2 solenoid.
  pinMode(CO2_PURGE_SOL, OUTPUT);

  // Fill rail solenoid.
  pinMode(FILL_RAIL_SOL, OUTPUT);

  // Beer belt solenoid.
  pinMode(BEER_BELT_SOL, OUTPUT);

  // Fill sensors.
  pinMode(BEER_FILL_SENSOR_1, INPUT);
  pinMode(BEER_FILL_SENSOR_2, INPUT);
  pinMode(BEER_FILL_SENSOR_3, INPUT);
  pinMode(BEER_FILL_SENSOR_4, INPUT);
  pinMode(BEER_FILL_SENSOR_POT, INPUT);

  // Start/Stop button.
  pinMode(START_BUTTON, INPUT);
  
  // Auto button.
  pinMode (AUTO_BUTTON, INPUT);

  // Caper solenoid.
  pinMode(CAPER_SOL, OUTPUT);
}

/**
 * Setup a non-blocking interrupt timer for checking the fill sensors.
 */
void setupFillSensorsTimer() {
  Timer1.initialize(FILL_SENSORS_TIMER_FREQUENCY);
  Timer1.attachInterrupt(checkFillSensors);
}

/**
 * Check if the fill sensors have been triggered.
 */
void checkFillSensors() {
    if (VARIABLE_FILL_SENSOR_TRIGGER) {
    sensorValue = analogRead(BEER_FILL_SENSOR_POT);
  } else {
    sensorValue = FILL_SENSORS_TRIGGER;
  }
  //Serial.println(sensorValue);
  if (sensorValue < analogRead(BEER_FILL_SENSOR_1)) {
    triggerFullFillSensor1();
  }
  if (sensorValue < analogRead(BEER_FILL_SENSOR_2)) {
    triggerFullFillSensor2();
  }
  if (sensorValue < analogRead(BEER_FILL_SENSOR_3)) {
    triggerFullFillSensor3();
  }
  if (sensorValue < analogRead(BEER_FILL_SENSOR_4)) {
    triggerFullFillSensor4();
  }
}

/**
 * Fired when fill sensor 1 is triggered as full.
 */
void triggerFullFillSensor1() {
  if (!fillSensor1Triggered && hasProgramState(FILLING)) {
    closeBeerFillerTube(BEER_INLET_SOL_1);
    fillSensor1Triggered = true;
    Serial.println("Filler tube 1 closed");
  }
}

/**
 * Fired when fill sensor 1 is triggered as full.
 */
void triggerFullFillSensor2() {
  if (!fillSensor2Triggered && hasProgramState(FILLING)) {
    closeBeerFillerTube(BEER_INLET_SOL_2);
    fillSensor2Triggered = true;
    Serial.println("Filler tube 2 closed");
  }
}

/**
 * Fired when fill sensor 1 is triggered as full.
 */
void triggerFullFillSensor3() {
  if (!fillSensor3Triggered && hasProgramState(FILLING)) {
    closeBeerFillerTube(BEER_INLET_SOL_3);
    fillSensor3Triggered = true;
    Serial.println("Filler tube 3 closed");
  }
}

/**
 * Fired when fill sensor 1 is triggered as full.
 */
void triggerFullFillSensor4() {
  if (!fillSensor4Triggered && hasProgramState(FILLING)) {
    closeBeerFillerTube(BEER_INLET_SOL_4);
    fillSensor4Triggered = true;
    Serial.println("Filler tube 4 closed");
  }
}


/**
 * Return whether all fill sensors have been triggered or not.
 */
bool allFillSensorsTriggered() {
  return fillSensor1Triggered && fillSensor2Triggered && fillSensor3Triggered && fillSensor4Triggered;
}

void resetFillSensorTriggers() {
  fillSensor1Triggered = fillSensor2Triggered = fillSensor3Triggered = fillSensor4Triggered = false;
}

/**
 * Open a single beer filler solenoid.
 */
void openBeerFillerTube(int fillerTubePin) {
  digitalWrite(fillerTubePin, HIGH);
}

/**
 * Close a single beer filler solenoid.
 */
void closeBeerFillerTube(int fillerTubePin) {
  digitalWrite(fillerTubePin, LOW);
}

/**
 * Open all beer filler solenoids.
 */
void openAllBeerFillerTubes() {
  Serial.println("Opening all beer filler tubes");
  lcd.print("Opening all beer    filler tubes");
  digitalWrite(BEER_INLET_SOL_1, HIGH);
  digitalWrite(BEER_INLET_SOL_2, HIGH);
  digitalWrite(BEER_INLET_SOL_3, HIGH);
  digitalWrite(BEER_INLET_SOL_4, HIGH);
  delay (4000);
  lcd.clear();
}

/**
 * Close all beer filler solenoids.
 */
void closeAllBeerFillerTubes() {
  Serial.println("Closing all beer filler tubes");
  lcd.print ("Closing all beer filler tubes");
  digitalWrite(BEER_INLET_SOL_1, LOW);
  digitalWrite(BEER_INLET_SOL_2, LOW);
  digitalWrite(BEER_INLET_SOL_3, LOW);
  digitalWrite(BEER_INLET_SOL_4, LOW);
  lcd.clear();
}

/**
 * Open the CO2 purge solenoid, wait a while and then close it again.
 */
void purgeCO2( bool retract = false ) {
  Serial.println("Purging CO2");
  lcd.print ("Purging CO2");
  digitalWrite(CO2_PURGE_SOL, HIGH);
  if(!retract) {
    delay(CO2_PURGE_PERIOD);
  } else {
    delay(CO2_PURGE_RETRACTION_PERIOD);
  }
  digitalWrite(CO2_PURGE_SOL, LOW);
  lcd.clear();
}

/**
 * Raise the fillter tubes out of the bottles.
 */
void raiseFillerTubes() {
  Serial.println("Raising filler tubes");
  lcd.setCursor(0,1);
  lcd.print ("Raising filler tubes");
  delay(RAISING_FILLER_TUBES_DELAY);
  digitalWrite(FILL_RAIL_SOL, HIGH);
  delay(CO2_PURGE_RETRACTION_DELAY); // We use CO2_PURGE_RETRACTION_DELAY here as we want to start purging with CO2 as the fill rail raises.
  lcd.clear();
}

/**
 * Lower the filler tubes into the bottles.
 */
void lowerFillerTubes() {
  Serial.println("Lowering filler tubes");
  lcd.print ("Lowering filler tube");
  digitalWrite(FILL_RAIL_SOL, LOW);
  delay(FILLER_TUBE_MOVEMENT_DELAY);
  lcd.clear();
}

/**
 * Move the beer belt, wait a while and then stop it again.
 */
void moveBeerBelt() {
  Serial.println( "Moving beer belt" );
  lcd.print ( "Moving beer belt" );
  digitalWrite(BEER_BELT_SOL, HIGH);
  delay(MOVE_BEER_BELT_PERIOD);
  digitalWrite(BEER_BELT_SOL, LOW);
  lcd.clear();
}

/**
 * Code to run when we are in the IDLE ProgramState
 */
void idleState() {
  if (!idleMessageDisplayed) {
    Serial.println("Press Start Button to proceed");
    lcd.print("Press Start ");
    idleMessageDisplayed = true;
  }
  readStartButton();
}

/**
 * Code to run when we are in the START ProgramState
 */
 void moveCaper() {
 Serial.println( "Caping");
 lcd.print( "Capping");
 digitalWrite(CAPER_SOL, HIGH);
 delay(CAPER_PERIOD);
 digitalWrite(CAPER_SOL, LOW);
 lcd.clear();
 }

/**
 * Code to run when we are in the START ProgramState.
 */
void startState() { 
  moveBeerBelt();
  moveCaper();
  lowerFillerTubes();
  purgeCO2();
  openAllBeerFillerTubes();
  changeProgramState(FILLING);
}

/**
 * Code to run when we are in the FILLING ProgramState.
 */
void fillingState() {
  // Check if we are done filling.
  if(allFillSensorsTriggered()){
    lcd.print("Filling Complete");
    raiseFillerTubes();
    purgeCO2(true);
    resetFillSensorTriggers();
    // If done filling, check if we want to do continuous filling or go back to the UNDEF state.
    #if defined(CONINUOUS_FILLING)
      changeProgramState(START);
    #else
      changeProgramState(IDLE);
    #endif
  }
}

/**
 * Code to run when we are in the STOP ProgramState.
 */
void stopState() {
  // Reset the sensors and change ProgramState to UNDEF.
  resetUnit();
  changeProgramState(IDLE);
}

/**
 * Read the start button.
 */
void readStartButton() {
  if(
    HIGH==digitalRead(START_BUTTON)
    && hasProgramState(IDLE)
  ) {
    Serial.println("Start Button Pressed");
    changeProgramState(START);
  }
}

/**
 * Read the stop button.
 */
void readStopButton() {
  if(
    HIGH==digitalRead(START_BUTTON)
    && !hasProgramState(IDLE)
    && !hasProgramState(START)
  ) {
    Serial.println("Stop Button Pressed");
    lcd.print ("Stop Button Pressed");
    changeProgramState(STOP);
  }
}

/**
 * Read the auto button.
 */
 void readAutoButton(){
  if(
    HIGH==digitalRead(AUTO_BUTTON)
    && !hasProgramState(IDLE)
  ) {
    Serial.println("Auto Mode active");
    lcd.print ("Auto Mode active");
    #define CONINUOUS_FILLING
  }
 }
/**
 * Reset the unit,
 */
void resetUnit() {
  Serial.println("Reseting unit");
  closeAllBeerFillerTubes();
  digitalWrite(BEER_BELT_SOL, LOW);
  raiseFillerTubes();
  digitalWrite(CO2_PURGE_SOL, LOW);
  Serial.println("Done resetting unit");
  changeProgramState(IDLE);
}

/**
 * Change the ProgramState
 */
void changeProgramState(ProgramState state) {
  // Reset the bool to avoid the IDLE state message to repeat continiously.
  if (IDLE == state){
    idleMessageDisplayed = false;
  }
  currentState = state;
  Serial.print("Program state changed: ");
  Serial.println(currentState);
}

/**
 * Check if the currentState matches the passed state.
 */
bool hasProgramState(ProgramState state) {
  if(state == currentState) {
    return true;
  }
  return false;
}

/**
 * Code in this function must always run, avoid delays in here.
 */
void alwaysRun() {
  readStopButton();
}

/**
 * ***************************************************************************
 * ***************************** MAIN FUNCTIONS ******************************
 * ***************************************************************************
 */

/**
 * Main setup routine.
 */
void setup() {
  Serial.begin(115200);//Serial.begin(9600);
  setupPins();
  setupFillSensorsTimer();
  resetUnit();
  lcd.begin(); // initialize the LCD
 
}

/**
 * The main program loop, where all the magic comes togetger.
 */
void loop() {
  lcd.setCursor(0,4);
  lcd.print ("Trigger Value")+(sensorValue);
  lcd.setCursor(14,4);
  lcd.print (sensorValue);
  delay(500);
  lcd.setCursor(15,4);
  lcd.print("     ");
  switch(currentState) {
    case IDLE:
      idleState();
      break;
    case START:
      startState();
      break;
    case FILLING:
      fillingState();
      break;
    case STOP:
      stopState();
      break;
  }
  alwaysRun();
}

Please supply a link to the original project.

By the way, just in case the problem is a typo, it's "continuous" not "coninuous".

what i have tried to do is have a puch button (pullup) to acitavte/diactivate this function. so is the any of you uote there that can help me with this.

Fix the spelling as previously suggested.

I would change the conditional compiler instruction with a boolean variable. Best practice would also change the name to camel case instead of the all caps used for constants.

You also need to actually call readAutoButton() in your program.

Try these changes

//#define CONINUOUS_FILLING // Uncomment this to have the filling process repeat for new batch after the current batch has completed it filling.

boolean CONINUOUS_FILLING = false;

/*
#if defined(CONINUOUS_FILLING)
      changeProgramState(START);
    #else
      changeProgramState(IDLE);
    #endif
  }
*/

if(CONINUOUS_FILLING)
      changeProgramState(START);
    else
      changeProgramState(IDLE);
  }

/*
void readAutoButton(){
  if(
    HIGH==digitalRead(AUTO_BUTTON)
    && !hasProgramState(IDLE)
  ) {
    Serial.println("Auto Mode active");
    lcd.print ("Auto Mode active");
    #define CONINUOUS_FILLING
  }
*/

void readAutoButton(){
  if(
    HIGH==digitalRead(AUTO_BUTTON)
    && !hasProgramState(IDLE)
  ) {
    Serial.println("Auto Mode active");
    lcd.print ("Auto Mode active");
    CONINUOUS_FILLING = true
  }

waw i saw that now . somthing to correct. link to the original project:

Here is the original code:

 * Code to run when we are in the FILLING ProgramState.
 */
void fillingState() {
  // Check if we are done filling.
  if(allFillSensorsTriggered()){
    raiseFillerTubes();
    purgeCO2(true);
    resetFillSensorTriggers();
    // If done filling, check if we want to do continuous filling or go back to the UNDEF state.
    #if defined(CONINUOUS_FILLING)
      changeProgramState(START);
    #else
      changeProgramState(IDLE);
    #endif;
  }
}

CONINUOUS?
Misspelling is ok as long as it's always misspelled the same way.

Here's how you detect if a "CONINUOUS_FILLING" switch is on or off.
(I'll leave it to you to add the switch code in your loop function).

 * Code to run when we are in the FILLING ProgramState.
 */
void fillingState() {
  // Check if we are done filling.
  if(allFillSensorsTriggered()){
    raiseFillerTubes();
    purgeCO2(true);
    resetFillSensorTriggers();
    // If done filling, check if we want to do continuous filling or go back to the UNDEF state.
	if (CONINUOUS_FILLING==true){
      changeProgramState(START);
    }else{
      changeProgramState(IDLE);
    }
  }
}

Not necessary for this project, but if you start to get low on SRAM, get into the habit of using the "F" function, like this:

from Serial.println("Caping");
to Serial.println(F("Caping"));

The F() tells the compiler, through a massively complex way that mere mortals can't comprehend, that the string constant is to be stored only in PROGMEM (code memory). This saves SRAM (data memory).

Just a good habit to get into.

can you describe what the code does and what you would like it to do? (is this for an automated factory-is line that fills multiple bottles of beer at a time)?

there's 458 lines of somewhat awkward code to reverse engineer.

(yes, i know you probably don't want to rewrite this code)

a typical state machine would monitor for stimuli, potentially change state and perform some action with each transition. this code. an action wouldn't typically be a series of events each taking more time than a button could be pressed in.

your code has separate functions to read each button that seem to be called in specific states.

it would be better for loop() to check for a button press from any button, as well a timer and other sensor inputs and for the actions for those stimuli to be dependent on the state. such an approach would make the code more maintainable (easier to read, modify, debug, enhance).

a button press could interrupt/stop the current processing step

you haven't specified which button you would like to add or process differently

seems like many of the functions should be a sequence of states with timeouts and allowing loop() to recognize a button press to abort or change processing

i don't see any error handling (do bottles just end up on the floor)? what happens if some sensor is not triggered within some period of time?

a common routine could be used to display strings both on the lcd and to the serial monitor which would simplify and reduce the size of the code.

...

so, it's now posible to activate the auto mode but i can't get the auto function to diactivate. a can't see what i'm doing wrong here.

bool idleMessageDisplayed = false;
enum ProgramState {UNDEF,IDLE,START,FILLING,STOP};
ProgramState currentState = UNDEF;
int sensorValue;
boolean CONINUOUS_FILLING = false;

/**
 * Code to run when we are in the FILLING ProgramState.
 */
void fillingState() {
  // Check if we are done filling.
  if(allFillSensorsTriggered()){
    lcd.print("Filling Complete");
    raiseFillerTubes();
    purgeCO2(true);
    resetFillSensorTriggers();
    readAutoButton();
    // If done filling, check if we want to do continuous filling or go back to the UNDEF state.
    if (CONINUOUS_FILLING==true){
      changeProgramState(START);
    }else{
      changeProgramState(IDLE);
  }
}
}
/**

void readAutoButton(){
  if(
    HIGH==digitalRead(AUTO_BUTTON)
    && !hasProgramState(IDLE)
  ) {
    Serial.println("Auto Mode active");
    lcd.print ("Auto Mode active");
    CONINUOUS_FILLING = true;
  }
}
/**
 * Code in this function must always run, avoid delays in here.
 */
void alwaysRun() {
  readStopButton();
  readAutoButton();
}

/**

You really aren't honouring the requests - you were asked, "can you describe what the code does and what you would like it to do?".

I can't see that you have made any attempt to modify the readAutoButton() function to add a condition to set CONINUOUS_FILLING = false.

What have you tried?

It's not clear from what has been posted when buttons are read in the program, and you may be better off with a toggle switch to set auto on and off rather than trying to time a push button reading.

What the code is doing is first moving that bottle forward and then activate the capping. After that lowering the four filler tube's. When that filling process is active there are a sensor that detecting the level in the bottle. This is individual done for each bottle. After the filling process is complete the program goes back to Idle. In the original code there is an define. Continues filling that i want to be able to activate and deactivate through a switch.

The code you need would be in a part of the code that you didn't post.
As I said, in loop() you need to read the state of the continuous fill switch.

after some late hours last night i finaly got it to work as i want to.
now the loop() starts with the readAutoButton before continuous with the rest of the loop.
thanks to everybody.

void readAutoButton(){
  if(
    HIGH==digitalRead(AUTO_BUTTON)
    && !hasProgramState(IDLE)
  ) {
    Serial.println("Auto Mode active");
    lcd.print ("Auto Mode active");
    CONINUOUS_FILLING = true;
  }
  else if (
    LOW==digitalRead(AUTO_BUTTON)
  ) {
    CONINUOUS_FILLING = false;
  }
  
}

/**
 * Code in this function must always run, avoid delays in here.
 */
void alwaysRun() {
  readStopButton();
  readAutoButton();
  readCipButton();
}

/**
 * The main program loop, where all the magic comes togetger.
 */
void loop() {
  lcd.setCursor(0,0);
  lcd.print ("Trigger Value")+(sensorValue);
  lcd.setCursor(14,0);
  lcd.print (sensorValue);
  delay(500);
  switch(currentState) {
    case IDLE:
      idleState();
      break;
    case CIP:
      cipState();
      break;
    case START:
      startState();
      break;
    case FILLING:
      fillingState();
      break;
    case STOP:
      stopState();
      break;
  }
  alwaysRun();
}