Little help with Potentiometer

So I’ve got a project for a weather system to just view current and the next two days forecasts.

It works well, but I wanted to use a Potentiometer as a sort of “menu selection” kind of thing.

What I want is;

Turn potentiometer once to the right = Display Tomorrow’s Forecast

Turn potentiometer once to the left = Display The Day After’s Forecast

Turn the potentiometer 2+ to the right = Refresh Weather Data

Turn the potentiometer 2+ to the left = Display Today’s Forecast

Now, this code I did works alright, but its very particular and not efficient, so looking for some help on getting it right.

void loop() {
  dataChange = false;

  aVal = digitalRead(rotaryA);
  if (aVal != pinALast) { // Means the knob is rotating
    findRange = 0;
    // if the knob is rotating, we need to determine direction
    // We do that by reading pin B.
    if (digitalRead(rotaryB) != aVal) {  // Means pin A Changed first - We're Rotating Clockwise
      encoderPosCount ++;
    } else {// Otherwise B changed first and we're moving CCW
      encoderPosCount--;
    }

    if (encoderPosCount > previousPosCount) {
      aVal = digitalRead(rotaryA);
      if (aVal > 0) {
        display.clearDisplay();
        display.ssd1306_command(SSD1306_DISPLAYON);
        display.setCursor(0, 10);
        display.println("Refreshing...");
        display.display();
        getWeatherData();
        displayCurrentData();
        dataChange = true;

      }

    }

    if (encoderPosCount < previousPosCount) {
      aVal = digitalRead(rotaryA);
      if (aVal > 0) {
        display.clearDisplay();
        display.ssd1306_command(SSD1306_DISPLAYON);
        displayCurrentData();
        dataChange = true;

      }

    }


    if (encoderPosCount > previousPosCount) {
      display.ssd1306_command(SSD1306_DISPLAYON);
      displayforecastA();
      dataChange = true;

    }

    if (encoderPosCount < previousPosCount) {
      display.ssd1306_command(SSD1306_DISPLAYON);
      displayforecastB();
      dataChange = true;

    }

    pinALast = aVal;
    previousPosCount = encoderPosCount;

  }

  if (dataChange == true) {
    stateChange = true;
    dataChange = false;
    delay(5000);

  }

  if (dataChange == false) {
    if (stateChange == true) {
      display.ssd1306_command(SSD1306_SETCONTRAST);
      display.ssd1306_command(0); // Where c is a value from 0 to 255 (sets contrast e.g. brightness)
      display.ssd1306_command(SSD1306_DISPLAYOFF);
      stateChange = false;
    }

  }

}

Is it a “normal” potentiometer with end-stops or something that allows continuous rotation?

Apologize I mispoke. It's a rotary encoder, not a potentiometer. A KY-040 to be exact

Me:
The problem is in the code you didn't post

Please post the complete code with the #include's and the setup() function.

RDaugherty:

    if (encoderPosCount > previousPosCount) {

aVal = digitalRead(rotaryA);

You already determined that the encoder had moved. You should not be reading the pin again. What if it moved during the microsecond that you were doing other stuff and now you have two different readings that you thought were the same thing but are actually different?

If you need to do something different for "odd" clicks of the encoder then check if the count is odd or even.

Not quite sure how the entirety of the code can help, but sure.

#include <Arduino.h>
#include <ESP8266WiFi.h>
#include "OpenWeatherMapCurrent.h"
#include "OpenWeatherMapForecast.h"
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>


#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)

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

OpenWeatherMapCurrent client;
OpenWeatherMapForecast client2;
String OPEN_WEATHER_MAP_APP_ID = "XXXXXXXX";
String OPEN_WEATHER_MAP_LOCATION_ID = "4259671";
String OPEN_WEATHER_MAP_LANGUAGE = "en";
boolean IS_METRIC = false;
uint8_t MAX_FORECASTS = 2;

int rotaryA = 14;  // Connected to CLK on KY-040
int rotaryB = 12;  // Connected to DT on KY-040
int rotaryButton = 13;
int encoderPosCount = 0;
int pinALast;
int previousPosCount = 0;
int aVal;
boolean bCW;
int findRange = 0;

boolean stateChange;
boolean dataChange;


String currentCondition;
float currentTemp;
float lowTemp;
float highTemp;
float pressure;
float humidity;
float windSpeed;
float windDeg;

String dayACondition;
float dayATemp;
float dayAHigh;
float dayALow;
float dayAPressure;
float dayAHumidity;
float dayASpeed;
float dayADeg;
float dayAChance;

String dayBCondition;
float dayBTemp;
float dayBHigh;
float dayBLow;
float dayBPressure;
float dayBHumidity;
float dayBSpeed;
float dayBDeg;
float dayBChance;

const char* ESP_HOST_NAME = "esp-" + ESP.getFlashChipId();
const char* WIFI_SSID     = "XXXXXXXXXX";
const char* WIFI_PASSWORD = "XXXXXX";
WiFiClient wifiClient;




void connectWifi() {

  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected!");
  Serial.println(WiFi.localIP());
  Serial.println();
}


void setup() {

  pinMode (rotaryA, INPUT);
  pinMode (rotaryB, INPUT);
  pinMode(rotaryButton, INPUT_PULLUP);
  pinALast = digitalRead(rotaryA);

  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(0, 10);
  display.println("Connecting to WiFi....");
  display.display();

  Serial.begin(115200);
  delay(500);
  connectWifi();

  display.clearDisplay();
  display.setCursor(0, 10);
  display.println("Connected! Getting Weather Data...");
  display.display();

  display.ssd1306_command(SSD1306_DISPLAYON);
  display.ssd1306_command(255);

  stateChange = true;

  getWeatherData();
  displayCurrentData();

}

void loop() {
  dataChange = false;

  aVal = digitalRead(rotaryA);
  if (aVal != pinALast) { // Means the knob is rotating
    findRange = 0;
    // if the knob is rotating, we need to determine direction
    // We do that by reading pin B.
    if (digitalRead(rotaryB) != aVal) {  // Means pin A Changed first - We're Rotating Clockwise
      encoderPosCount ++;
    } else {// Otherwise B changed first and we're moving CCW
      encoderPosCount--;
    }

    if (encoderPosCount > previousPosCount) {
      aVal = digitalRead(rotaryA);
      if (aVal > 0) {
        display.clearDisplay();
        display.ssd1306_command(SSD1306_DISPLAYON);
        display.setCursor(0, 10);
        display.println("Refreshing...");
        display.display();
        getWeatherData();
        displayCurrentData();
        dataChange = true;

      }

    }

    if (encoderPosCount < previousPosCount) {
      aVal = digitalRead(rotaryA);
      if (aVal > 0) {
        display.clearDisplay();
        display.ssd1306_command(SSD1306_DISPLAYON);
        displayCurrentData();
        dataChange = true;

      }

    }


    if (encoderPosCount > previousPosCount) {
      display.ssd1306_command(SSD1306_DISPLAYON);
      displayforecastA();
      dataChange = true;

    }

    if (encoderPosCount < previousPosCount) {
      display.ssd1306_command(SSD1306_DISPLAYON);
      displayforecastB();
      dataChange = true;

    }

    pinALast = aVal;
    previousPosCount = encoderPosCount;

  }

  if (dataChange == true) {
    stateChange = true;
    dataChange = false;
    delay(5000);

  }

  if (dataChange == false) {
    if (stateChange == true) {
      display.ssd1306_command(SSD1306_SETCONTRAST);
      display.ssd1306_command(0); // Where c is a value from 0 to 255 (sets contrast e.g. brightness)
      display.ssd1306_command(SSD1306_DISPLAYOFF);
      stateChange = false;
    }

  }

}


void getWeatherData() {
  OpenWeatherMapCurrentData data;
  client.setLanguage(OPEN_WEATHER_MAP_LANGUAGE);
  client.setMetric(IS_METRIC);
  client.updateCurrentById(&data, OPEN_WEATHER_MAP_APP_ID, OPEN_WEATHER_MAP_LOCATION_ID);

  currentCondition = data.description.c_str();
  currentTemp = data.temp;
  lowTemp = data.tempMin;
  highTemp = data.tempMax;
  pressure = data.pressure;
  humidity = data.humidity;
  windSpeed = data.windSpeed;
  windDeg = data.windDeg;


  OpenWeatherMapForecastData data2[MAX_FORECASTS];
  client2.setMetric(IS_METRIC);
  client2.setLanguage(OPEN_WEATHER_MAP_LANGUAGE);
  uint8_t allowedHours[] = {0, 12};
  client2.setAllowedHours(allowedHours, 2);
  uint8_t foundForecasts = client2.updateForecastsById(data2, OPEN_WEATHER_MAP_APP_ID, OPEN_WEATHER_MAP_LOCATION_ID, MAX_FORECASTS);
  time_t time;

  dayACondition = data2[0].description.c_str();
  dayAHigh = data2[0].tempMax;
  dayALow = data2[0].tempMin;
  dayAPressure = data2[0].pressure;
  dayAHumidity = data2[0].humidity;
  dayASpeed = data2[0].windSpeed;
  dayADeg = data2[0].windDeg;
  dayAChance = data2[0].rain;

  dayBCondition = data2[1].description.c_str();
  dayBHigh = data2[1].tempMax;
  dayBLow = data2[1].tempMin;
  dayBPressure = data2[1].pressure;
  dayBHumidity = data2[1].humidity;
  dayBSpeed = data2[1].windSpeed;
  dayBDeg = data2[1].windDeg;
  dayBChance = data2[1].rain;
}

void displayCurrentData() {

  display.clearDisplay();
  display.setCursor(0, 0);
  display.println("Selection: Today");
  display.print("Con.:");
  display.println(currentCondition);
  display.print("Temp:");
  display.println(currentTemp);
  display.print("High:");
  display.print(highTemp);
  display.print(" Low:");
  display.println(lowTemp);
  display.print("Pressure:");
  display.println(pressure);
  display.print("Humidity:");
  display.println(humidity);
  display.print("Wind Speed:");
  display.println(windSpeed);
  display.print("Wind Direction:");
  display.println(windDeg);
  display.display();

}

void displayforecastA() {

  display.clearDisplay();
  display.setCursor(0, 0);
  display.println("Selection: Tomorrow");
  display.print("Con.:");
  display.println(dayACondition);
  display.print("High:");
  display.print(dayAHigh);
  display.print(" Low:");
  display.println(dayALow);
  display.print("Pressure:");
  display.println(dayAPressure);
  display.print("Humidity:");
  display.println(dayAHumidity);
  display.print("Wind Speed:");
  display.println(dayASpeed);
  display.print("Wind Direction:");
  display.println(dayADeg);
  display.print("Perc. %:");
  display.println(dayAChance);
  display.display();

}

void displayforecastB() {

  display.clearDisplay();
  display.setCursor(0, 0);
  display.println("Selection: Day After");
  display.print("Con.:");
  display.println(dayBCondition);
  display.print("High:");
  display.print(dayBHigh);
  display.print(" Low:");
  display.println(dayBLow);
  display.print("Pressure:");
  display.println(dayBPressure);
  display.print("Humidity:");
  display.println(dayBHumidity);
  display.print("Wind Speed:");
  display.println(dayBSpeed);
  display.print("Wind Direction:");
  display.println(dayBDeg);
  display.print("Perc. %:");
  display.println(dayBChance);
  display.display();

}

As for needing to count even/odd. That COULD be a solution but I guess my main goal is;

Create a loop that starts when the encoder is turned, count how many turns one way or the other and exits once you stop spinning the encoder.

With that number of counts I can call X Sub.

RDaugherty:
Not quite sure how the entirety of the code can help, but sure.

Many people have asked questions about code snippets that they thought had a problem when, in fact, the problem was in another part of the program that they had not been scrutinizing.

You have to understand that you have a huge amount of background information about your project and we have none of it. I (and I suspect others) need to get a good overall picture before any single piece makes sense.

And maybe the overall picture is just needed so I can be sure that I don't need to wonder about code in some other corner of the program.

...R

RDaugherty:
Not quite sure how the entirety of the code can help, but sure.
...snip...

Well now we know you are using an ESP with 32-bit integers.

Create a loop that starts when the encoder is turned, count how many turns one way or the other and exits once you stop spinning the encoder.

With that number of counts I can call X Sub.

Don't do that. Think of it more like a loop that loops very fast. It reads all the inputs and makes decisions based on those inputs. That is your whole program.

If one of those inputs has changed (encoder clicked over) then update the screen or whatever you need to do. That should only take a few microseconds and you can go back to reading the inputs.

Remember what screen you are on, because the buttons will have different effects on the different screens.