COFFEE Needing help with an ESP32 project




Very new to arduino and programming in general.
brief explanation of my project - i have been restoring old espresso machine for some time and recent wanted to incorporate some basic smarts into an old manual machine.

The machine has two group heads, (water outlets), flick a switch on and the water comes out, flick the switch off and the water turns off. The amount of water out is basically a ratio of how much coffee you start with and extracting that amount of water over an acceptable amount of time.
ie 20grams of coffee at a ratio of 3:1 = 60ml of water.

My hardware setup is as follows
ESP32Node32s
2x momentary buttons
1x 2 channel relay

desired outcome -
push button - relay activate for 25sec then turns off

at anytime i can interrupt by pressing the button again.

I have been able to code with success pushing either button to turn on or off the relays but can't work out how to add the run time. I have been researching and following tutorials and watching youtube and have been unsuccessful in getting any working result. When finding something remotely close and asking the creator for assistance im general met with "research millis and add that to you code"... im now having dreams about millis i have read so much and watched tutorials for the past 2 weeks and still can't seem to work it out...

the link is to the code that has no millis yet added. this is a sketch i have modified from an online tutorial which im happy with todate.

I'd really appreciate some help with one

/*
 * 
 */
const int pushButton[] ={22,23};// button inputs
const int relayPin[]={26,27};// output pins relays
String relayNames[] ={"CH1", "CH2"};// name for relays
int pushed[] ={0,0};// status of each buttons
int relayStatus[] ={HIGH,HIGH};// initial status of relay


void setup() {
  Serial.begin(9600);// initialize serial monitor 
  for(int i=0; i<2; i++)
  {
    pinMode(pushButton[i], INPUT_PULLUP); 
    pinMode(relayPin[i], OUTPUT);   
    digitalWrite(relayPin[i], HIGH);// initial relay status to be OFF
  }

}

void loop() {

  for(int i=0; i<2; i++)
  {
     int  val = digitalRead(pushButton[i]);   
    if(val == HIGH && relayStatus[i] == LOW){
  
      pushed[i] = 1-pushed[i];
      delay(50);
    }// if   

  relayStatus[i] = val;

      if(pushed[i] == HIGH){
        Serial.print(relayNames[i]);
        Serial.println(" ON");
        digitalWrite(relayPin[i], LOW); 
       
      }else{
        Serial.print(relayNames[i]);
        Serial.println(" OFF");
        digitalWrite(relayPin[i], HIGH);
   
      }// else   
 
  }// for 
    Serial.println("=="); 
  delay(50);
  
}// loop end

you should not awake until end of dream.
after that read here:

Post your code in code tags, please.

Post the sechmatic.

Post a few images of the project.

thanks for your reply. I did attempt to share the sketch using the web editor but it appears have added a link to something else so sketch now in </> i hope i did it right.

is there an app i can use to create a schematic?

how do i ad a photo of my setup?

1 Like

You have several arrays for tracking status of each drink dispenser and all other related infos (input, output, name etc etc).

You could pack all in a struct and then declare an array of this defined struct.
In addition, you are running your code on a really powerful MCU, so why don't use some more modern C ++ range-based for in order to iterate each element of the array: You code will be clearer and more readable.

This is just a starting point.
For example as a first upgrade, I would avoid the possibility to select a new drink while machine is dispensing or add the possibility to define a different dispense time for each drink.

1 Like

Not feeling like hooking up relays and buttons I wrote this but did not test, most likely needs debugging.

#include "esp_system.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
////
SemaphoreHandle_t sema_btnState;
////
const int pushButton[] = {22, 23}; // button inputs
const int relayPin[] = {26, 27}; // output pins relays
String relayNames[] = {"CH1", "CH2"}; // name for relays
int pushed[] = {0, 0}; // status of each buttons
int relayStatus[] = {HIGH, HIGH}; // initial status of relay
////
void setup()
{
  Serial.begin(115200);
  sema_btnState = xSemaphoreCreateBinary();
  xSemaphoreGive( sema_btnState );
  for (int i = 0; i < 2; i++)
  {
    pinMode(pushButton[i], INPUT_PULLUP);
    pinMode(relayPin[i], OUTPUT);
    digitalWrite(relayPin[i], HIGH);// initial relay status to be OFF
  }

  xTaskCreatePinnedToCore( fButtonCheck, "fButtonCheck", 7000,  NULL, 3, NULL, 1 );
  xTaskCreatePinnedToCore( fDoTheThing, "fDoTheThing", 7000,  NULL, 5, NULL, 1 );
}
////
void fButtonCheck( void *pvparemeters )
{
  TickType_t xLastWakeTime = xTaskGetTickCount();
  const TickType_t xFrequency = 50; //delay for mS
  for (;;)
  {
    for (int i = 0; i < 2; i++)
    {
      if ( pushed[i] != digitalRead(pushButton[i]) )
{
        xSemaphoreTake( sema_btnState, portMAX_DELAY );
      pushed[i] = digitalRead(pushButton[i]);
      xSemaphoeGive( sema_btnState );
}
    }
    xLastWakeTime = xTaskGetTickCount();
    vTaskDelayUntil( &xLastWakeTime, xFrequency );// runs once every 50ms
  }
  vTaskDelete( NULL );
}  //void fButtonCheck( void *pvparemeters )
////
void fDoTheThing ( void *pvParemeters )
{
  TickType_t xLastWakeTime = xTaskGetTickCount();
  const TickType_t xFrequency = 10; //delay for mS
  
  for (;;)
  {
xSemaphoreTake( sema_btnState, portMAX_DELAY );
    for (int i = 0; i < 2; i++)
    {
      if ( pushed[i] )
      {
        Serial.print(relayNames[i]);
        Serial.println(" ON");
        digitalWrite(relayPin[i], LOW);
      } else {
        Serial.print(relayNames[i]);
        Serial.println(" OFF");
        digitalWrite(relayPin[i], HIGH);
      }
      Serial.println("==");
    }//
    xSemaphoeGive( sema_btnState );
    xLastWakeTime = xTaskGetTickCount();
    vTaskDelayUntil( &xLastWakeTime, xFrequency );
  }
} //void fDoTheThing ( void *pvParemeters )
////
void loop() { }

The ESP32 has an OS called freeRTOS which the Arduino core runs on top of. This code is written using the ESP32's OS.

The program has 2 tasks, loop() need to remain empty. TaskfButtonCheck is checking the button state once every 50 milliseconds and records the button state. The task fDoTheThing is running once every 10 milliseconds and does the thing with the relays based upon the button state recorded.

I figured the button check task is running so slow because you are using 50ms for switch debouncing. I'd do hardware switch debouncing and run the button check task at 10ms as well.

Edit added Semaphore.

What will happen is when the button check task takes the semaphore, dothething task stops running. Remember dothething task is running very fast in relation to the buttoncheck task. With the semaphore take by the buttonchecktask complete the dothethingtask is allowed to continue and updates operations with the new button states.

Changed to putting each task on its own core, removed serial prints in favor ESP32's native log print, changed push to a Boolean from an int, and dropped buttonstate check down to 30 milliseconds.

#include "sdkconfig.h"
#include "esp_system.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
////
SemaphoreHandle_t sema_btnState;
////
const int pushButton[] = {22, 23}; // button inputs
const int relayPin[] = {26, 27}; // output pins relays
String relayNames[] = {"CH1", "CH2"}; // name for relays
bool pushed[] = {0,0}; // status of each buttons
int relayStatus[] = {HIGH, HIGH}; // initial status of relay
////
void setup()
{
  sema_btnState = xSemaphoreCreateBinary();
  xSemaphoreGive( sema_btnState );
  for (int i = 0; i < 2; i++)
  {
    pinMode(pushButton[i], INPUT_PULLUP);
    pinMode(relayPin[i], OUTPUT);
    digitalWrite(relayPin[i], HIGH);// initial relay status to be OFF
  }
  xTaskCreatePinnedToCore( fButtonCheck, "fButtonCheck", 7000,  NULL, 3, NULL, 1 ); //running on core 1
  xTaskCreatePinnedToCore( fDoTheThing, "fDoTheThing", 7000,  NULL, 5, NULL, 0 );  //running on core 0
 }
////
void fButtonCheck( void *pvparemeters )
{
  TickType_t xLastWakeTime = xTaskGetTickCount();
  const TickType_t xFrequency = 50; //delay for mS
  for (;;)
  {
    for (int i = 0; i < 2; i++)
    {
      if ( pushed[i] != digitalRead(pushButton[i]) )
      {
      xSemaphoreTake( sema_btnState, portMAX_DELAY );
      pushed[i] = !pushed[i];
      xSemaphoreGive( sema_btnState );
      }
    }
    xLastWakeTime = xTaskGetTickCount();
    vTaskDelayUntil( &xLastWakeTime, xFrequency );// runs once every 50ms
  }
  vTaskDelete( NULL );
}  //void fButtonCheck( void *pvparemeters )
////
void fDoTheThing ( void *pvParemeters )
{
  TickType_t xLastWakeTime = xTaskGetTickCount();
  const TickType_t xFrequency = 10; //delay for mS
  for (;;)
  {
    xSemaphoreTake( sema_btnState, portMAX_DELAY );
    for (int i = 0; i < 2; i++)
    {
      if (pushed[i])
      {
        log_i( "%d ON", relayNames[i]);
        digitalWrite(relayPin[i], LOW);
      } else {
        log_i( "%d OFF", relayNames[i]);
        digitalWrite(relayPin[i], HIGH);
      }
      log_i( "==" );
    }//
    xSemaphoreGive( sema_btnState );
    xLastWakeTime = xTaskGetTickCount();
    vTaskDelayUntil( &xLastWakeTime, xFrequency );
  }
} //void fDoTheThing ( void *pvParemeters )
////
void loop() { }
1 Like

Thank you Idahowalker for you your input and code suggestions. With the sketch you provided which value do i change to control the time the relay stays open for. Running the code provided the relays commence open and only close when i press the button but immediately return to open once i release the button.

Surely you can do some of your homework assignment by yourself.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.