Arduino IDE with a controller from MIT App Inventor

Hello,

I have an IoT project using Arduino ide code script. The controller for the code is from the MIT App Inventor application. My project is in the form of a timer with a time that has been set in the Arduino code script. I made start, pause, and resume buttons in the Arduino code script. My problem is that the pause and resume buttons don't work. Can you help me?

#include <Arduino.h>
#include "SSD1306.h"
#include "BluetoothSerial.h"

SSD1306 oled(0x3c, 21, 22); // SDA, SCL;
BluetoothSerial SerialBT;
#define led1 17
#define led2 18
#define led3 19
#define relay 14

unsigned long previousMillis = 0;
const long interval = 1000; // Interval 1 detik
bool TimerRunning = true;

// Timer 1
long minutes = 6;
long seconds = 0;
long countdown_time = (minutes * 60) + seconds;
unsigned long TimeRemaining = countdown_time * 1000ul;

// Timer 2
long minutes1 = 6;
long seconds1 = 0;
long countdown_time1 = (minutes1 * 60) + seconds1;
unsigned long TimeRemaining1 = countdown_time1 * 1000ul;

// Timer 3
long minutes2 = 11;
long seconds2 = 0;
long countdown_time2 = (minutes2 * 60) + seconds2;
unsigned long TimeRemaining2 = countdown_time2 * 1000ul;

// Timer 4
long minutes3 = 11;
long seconds3 = 0;
long countdown_time3 = (minutes3 * 60) + seconds3;
unsigned long TimeRemaining3 = countdown_time3 * 1000ul;


void setup() {
  oled.init();
  SerialBT.begin("ESP32-Bluetooth");
  oled.setContrast(255);
  oled.flipScreenVertically();
  oled.setTextAlignment(TEXT_ALIGN_LEFT);
  oled.display();
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
  pinMode(led3, OUTPUT);
  pinMode(relay, OUTPUT);
}

void loop() {
  while (SerialBT.available()) {
    char c = SerialBT.read();

    switch (c) {
      case '1':
        digitalWrite(relay, HIGH);
        break;
      case '0':
        digitalWrite(relay, LOW);
        break;
      case 'a':
        Timer1();
        break;
      case 'b':
        Timer2();
        break;
      case 'c':
        Timer3();
        break;
      case 'd':
        Timer4();
        break;
    }

    if ((minutes == 5 && seconds == 0) || (minutes1 == 5 && seconds1 == 0) || (minutes2 == 5 && seconds2 == 0) || (minutes3 == 5 && seconds3 == 0)) {
      digitalWrite(led1, HIGH);
      digitalWrite(led2, HIGH);
      digitalWrite(led3, HIGH);
      oled.setFont(ArialMT_Plain_16);
      oled.drawString(9, 10, "Istirahat");
      oled.display();
    } else if ((minutes == 0 && seconds == 0) || (minutes1 == 0 && seconds1 == 0) || (minutes2 == 0 && seconds2 == 0) || (minutes3 == 0 && seconds3 == 0)) {
      digitalWrite(led1, LOW);
      digitalWrite(led2, LOW);
      digitalWrite(led3, LOW);
      oled.setFont(ArialMT_Plain_16);
      oled.drawString(30, 10, "Selesai");
      oled.display();
      while (true) {
      }
    }
  }
}

void Timer1() {                   //Syarat timer, pause, resume 1
  if (SerialBT.available()) {
    char c = SerialBT.read();
    while(true) {
    if (c == '2') {
        TimerRunning = true;
        if (TimerRunning) {
          unsigned long currentMillis = millis();
          if (currentMillis - previousMillis >= interval) {
            if (seconds > 0) {
              seconds--;
            } else if (minutes > 0) {
              minutes--;
              seconds = 59;
            }
            oled.setFont(ArialMT_Plain_24);
            oled.drawString(40, 28, String(minutes) + ":" + String(seconds));
            oled.display();
            previousMillis = currentMillis;
            }
          }

    if (SerialBT.available() > 0) {
      char c = SerialBT.read();

        if (c == '6') {
          if (TimerRunning) {
            TimerRunning = false;
            TimeRemaining = (minutes * 60 + seconds) * 1000 - (millis() - previousMillis);
            oled.setFont(ArialMT_Plain_16);
            oled.drawString(30, 10, "pause");
            oled.display();
            oled.clear();
          } else {
          if (!TimerRunning) {
            TimerRunning = true;
            previousMillis = millis();
            oled.setFont(ArialMT_Plain_16);
            oled.drawString(30, 10, "resume");
            oled.display();
            oled.clear();
            }
          }
        } 
      }
    }
  }
}
}

void Timer2() {                    //Syarat timer, pause, resume 2
  if (SerialBT.available()) {
    char c = SerialBT.read();
    while(true) {
    if (c == '3') {
      TimerRunning = true;
      if (TimerRunning) {
        unsigned long currentMillis = millis();
        if (currentMillis - previousMillis >= interval) {
          if (seconds1 > 0) {
            seconds1--;
          } else if (minutes1 > 0) {
            minutes1--;
            seconds1 = 59;
          }
          oled.setFont(ArialMT_Plain_24);
          oled.drawString(40, 28, String(minutes1) + ":" + String(seconds1));
          oled.display();
          previousMillis = currentMillis;
          }
        }

      if (SerialBT.available() > 0) {
        char c = SerialBT.read();

        if (c == '7') {
          if (TimerRunning) {
            TimerRunning = false;
            TimeRemaining1 = (minutes * 60 + seconds) * 1000 - (millis() - previousMillis);
            oled.setFont(ArialMT_Plain_16);
            oled.drawString(30, 10, "pause");
            oled.display();
            oled.clear();
          } else {
          if (!TimerRunning) {
            TimerRunning = true;
            previousMillis = millis();
            oled.setFont(ArialMT_Plain_16);
            oled.drawString(30, 10, "resume");
            oled.display();
            oled.clear();
            }
          }
        }
      }
    }
  }
}
}

void Timer3() {                     //Syarat timer, pause, resume 3
  if (SerialBT.available()) {
    char c = SerialBT.read();
    while(true) {
    if (c == '4') {
      TimerRunning = true;
      if (TimerRunning) {
        unsigned long currentMillis = millis();
        if (currentMillis - previousMillis >= interval) {
          if (seconds2 > 0) {
            seconds2--;
          } else if (minutes2 > 0) {
            minutes2--;
            seconds2 = 59;
          }
          oled.setFont(ArialMT_Plain_24);
          oled.drawString(40, 28, String(minutes2) + ":" + String(seconds2));
          oled.display();
          previousMillis = currentMillis;
          }
        }

      if (SerialBT.available() > 0) {
        char c = SerialBT.read();

        if (c == '8') {
          if (TimerRunning) {
          TimeRemaining2 = (minutes * 60 + seconds) * 1000 - (millis() - previousMillis);
          TimerRunning = false;
          oled.setFont(ArialMT_Plain_16);
          oled.drawString(30, 10, "pause");
          oled.display();
          oled.clear();
        } else {
          if (!TimerRunning) {
            previousMillis = millis();
            TimerRunning = true;
            oled.setFont(ArialMT_Plain_16);
            oled.drawString(30, 10, "resume");
            oled.display();
            oled.clear();
            }
          }
        }
      }
    }
  }
}
}

void Timer4() {                     //Syarat timer, pause, resume 4
  if (SerialBT.available()) {
    char c = SerialBT.read();
    while(true) {
    if (c == '5') {
        TimerRunning = true;
        if (TimerRunning) {
          unsigned long currentMillis = millis();
          if (currentMillis - previousMillis >= interval) {
            if (seconds3 > 0) {
              seconds3--;
            } else if (minutes3 > 0) {
              minutes3--;
              seconds3 = 59;
            }
            oled.setFont(ArialMT_Plain_24);
            oled.drawString(40, 28, String(minutes3) + ":" + String(seconds3));
            oled.display();
            previousMillis = currentMillis;
            }
          }

      if (SerialBT.available() > 0) {
        char c = SerialBT.read();

        if (c == '9') {
          if (TimerRunning) {
            TimerRunning = false;
            TimeRemaining3 = (minutes * 60 + seconds) * 1000 - (millis() - previousMillis);
            oled.setFont(ArialMT_Plain_16);
            oled.drawString(30, 10, "pause");
            oled.display();
            oled.clear();
          } else {
          if (!TimerRunning) {
            previousMillis = millis();
            TimerRunning = true;
            oled.setFont(ArialMT_Plain_16);
            oled.drawString(30, 10, "resume");
            oled.display();
            oled.clear();
            }
          }
        }
      }
    }
  }
}
}

This is more or less like the command in MIT App Inventor

image

The structure of this code doesn't make much sense.

void Timer1()
{  //Syarat timer, pause, resume 1
  if (SerialBT.available())
  {
    char c = SerialBT.read();
    while (true)
    {

In each Timer function, there is an infinite while() loop, is that intentional?

You have also got 4 copies of essentially the same Timer function, that is poor practice. It would be better to have a common function and pass it different parameters.

I can't see any similarity between your code and the picture.

Oh I get it, that is the application which sends commands to the Arduino.

It seems like you need functions like "startTimer(n)" and "pauseOrResumeTimer(n)" which are called from the main loop.

Yes, it's like that because if the while() condition is not given, the timer code cannot count down

I don't know about that, can you give an example?

That's right, sir

This looks like there is a timing issue. Should it wait for a character?

Can this be used for 4 types of timers at once?

Yes.

Yes sir. because there is a choice of which time to use

Ok, but then the following code is never executed :

 if ((minutes == 5 && seconds == 0) || (minutes1 == 5 && seconds1 == 0) || (minutes2 == 5 && seconds2 == 0) || (minutes3 == 5 && seconds3 == 0))
 {
   ...

I modified the sketch to use a single function, and adapted it to my OLED. A timer can be started, paused and resumed, but the function never returns. That doesn't really make sense to me, but that seems closest to how it was originally coded.

It would make more sense to me if each timer could be started, paused and resumed independently. However, you have not adequately defined your requirements.

#include <Arduino.h>
//#include "SSD1306.h"
//#include "BluetoothSerial.h"
#include <U8g2lib.h>

//SSD1306 oled(0x3c, 21, 22);  // SDA, SCL;
//BluetoothSerial SerialBT;
#define SerialBT Serial

#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif
U8G2_SSD1306_128X64_NONAME_F_HW_I2C oled(U8G2_R2, /* clock=*/SCL, /* data=*/SDA, /* reset=*/U8X8_PIN_NONE);  // High speed I2C

#define led1 17
#define led2 18
#define led3 19

#define relay 14

unsigned fontHeight;

void setup()
{
  //SerialBT.begin("ESP32-Bluetooth");
  Serial.begin(115200);

  oled.begin();
  //oled.setContrast(255);
  //oled.flipScreenVertically();
  //oled.setTextAlignment(TEXT_ALIGN_LEFT);
  //oled.display();
  oled.clearBuffer();                   // clear the internal memory
  oled.setFont(u8g2_font_10x20_mr   );   // choose a suitable font
  fontHeight = oled.getMaxCharHeight();

  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
  pinMode(led3, OUTPUT);
  pinMode(relay, OUTPUT);
}

void loop()
{
  while (SerialBT.available())
  {
    char c = SerialBT.read();

    switch (c)
    {
      case '1':
        digitalWrite(relay, HIGH);
        break;
      case '0':
        digitalWrite(relay, LOW);
        break;
      case 'a':
        runTimer('2', '6', 0, 10);
        break;
      case 'b':
        runTimer('3', '7', 6, 0);
        break;
      case 'c':
        runTimer('4', '8', 11, 0);
        break;
      case 'd':
        runTimer('5', '9', 11, 0);
        break;
    }

#if 0
    // this is never executed
    if ((minutes == 5 && seconds == 0) || (minutes1 == 5 && seconds1 == 0) || (minutes2 == 5 && seconds2 == 0) || (minutes3 == 5 && seconds3 == 0))
    {
      digitalWrite(led1, HIGH);
      digitalWrite(led2, HIGH);
      digitalWrite(led3, HIGH);
      oled.setFont(ArialMT_Plain_16);
      oled.drawString(9, 10, "Istirahat");
      oled.display();
    }
    else if ((minutes == 0 && seconds == 0) || (minutes1 == 0 && seconds1 == 0) || (minutes2 == 0 && seconds2 == 0) || (minutes3 == 0 && seconds3 == 0))
    {
      digitalWrite(led1, LOW);
      digitalWrite(led2, LOW);
      digitalWrite(led3, LOW);
      oled.setFont(ArialMT_Plain_16);
      oled.drawString(30, 10, "Selesai");
      oled.display();
      while (true)
      {
      }
    }
#endif
  }
}

void drawString(int x, int y, String s)
{
  oled.drawStr(x, y, s.c_str());
}

void runTimer(const char startKey, const char pauseKey, long minutes, long seconds)
{
  bool TimerRunning = false;
  unsigned long previousMillis = 0;
  const unsigned long interval = 1000;  // Interval 1 detik
  unsigned long TimeRemaining;

  drawString(0, fontHeight, "Run timer");
  oled.sendBuffer();

  //Syarat timer, pause, resume 1
  while (true)
  {
    if (TimerRunning)
    {
      unsigned long currentMillis = millis();
      if (currentMillis - previousMillis >= interval)
      {
        if (seconds > 0)
        {
          seconds--;
        }
        else if (minutes > 0)
        {
          minutes--;
          seconds = 59;
        }
        //oled.setFont(ArialMT_Plain_24);
        drawString(0, fontHeight*2, String(minutes) + ":" + String(seconds));
        //oled.display();
        oled.sendBuffer();
        previousMillis = currentMillis;
      }
    }

    if (SerialBT.available())
    {
      char c = SerialBT.read();
      
      if (c == startKey)
      {
        TimerRunning = true;
        previousMillis = millis();
      }
      else if (c == pauseKey)
      {
        if (TimerRunning)
        {
          TimerRunning = false;
          TimeRemaining = (minutes * 60 + seconds) * 1000 - (millis() - previousMillis);
          //oled.setFont(ArialMT_Plain_16);
          drawString(0, fontHeight*3, "pause ");
          //oled.display();
          oled.sendBuffer();
          //oled.clear();
        }
        else
        {
          TimerRunning = true;
          previousMillis = millis();
          //oled.setFont(ArialMT_Plain_16);
          drawString(0, fontHeight*3, "resume ");
          //oled.display();
          oled.sendBuffer();
          //oled.clear();
        }
      }
    }
  } // while
}

it can be executed sir because I put it in one curly brace with while()

Thank you for your generosity sir, I will try it after this

do I need to create buttons and conditions for each of those timers? what do you mean by making a void() like the previous code script?

thank you very much for your help sir, it worked as per my wish :grin:

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