Slider widget still jumping to zero

I am still having troubles with horizontal sliders jumping to zero occasionally when I use them. When it gets into this strange mode you can’t drag the slider but can click somewhere on the widget and the slider will move there. You can temporarily resolved the issue by switching to another project and come back to the original project.

I am using the latest Android app version 2.20.2 on a Samsung S7 version 7.0.

This issue isn’t new. I use the sliders only to send data to my devices and for setpoint and PID control and obviously when it jumps to zero causes bad things to happen.

Hello. Do you set slider value from the hardware side?

That is probably the result of your improper code. Some feedback loop or similar. I had very similar issue once, and all in all it showed my error, not Blynk :flushed:

No, the hardware does not drive the slider value. I only use the sliders to drive data from the app to the hardware.

Not likely as I only use the sliders to send data to the hardware and it temporarily resolves itself in the app by switching to a different project and then back again which would rule out anything on the hardware side.

@BlynkAndroidDev FYI.

I haven’t seen this issue in a long time now… also running Android v7.0 (on my daily driver phone, various other versions on other devices) and I use lots of sliders in many projects.

@DrDigital Have you reflashed all your projects with latest Library as well? What about the version of Local Server, if you use it?.. even though it seems an App issue, everything seems interrelated.

@Gunner I am using library 0.5.2 on a Wemos D1 mini device. I have compiled my code recently as well. I am not using a local server.

Can you provide code that can show the repeatability of the issue?

Here is a copy of the code:

cpp<#define VERSION "Brew 4.18.18D"
// Virtual pin maps 
// PUSH = data automatically sent to Blynk 
// PULL = Blynk will request the data
// WRITE = Blynk will send the data to the device
// V0 - PUSH  Temp C
// V1 - PUSH  Relay (output) State
// V2 - PUSH  Temperature Setpoint readback
// V3 - PULL  RSSI
// V4 - PULL  Version / Hostname / IP Address / SSID / BSSID / Auth Token
// V5 - PULL  Sensor read fails
// V6 - PULL  Sensor report fails
// V7 - WRITE Temperature Setpoint
// V8 - WRITE PID Mode AUTOMATIC/MANUAL
// V9 - WRITE PID Direction DIRECT/REVERSE
// V10 - WRITE PID Max Window Size
// V11 - WRITE PID Min Window Size
// V12 - WRITE PID Proportional on error or measurement P_ON_E/P_ON_M
// V13 - WRITE Kp PID Proportional
// V14 - WRITE Ki PID Integral
// V15 - WRITE Kd PID Derivative
// V16 - PUSH Output

#define MYDEBUG

// Blynk debug
#define BLYNK_PRINT Serial
//#define BLYNK_DEBUG

//Blynk Colors
#define BLYNK_GREEN     "#23C48E"
#define BLYNK_BLUE      "#04C0F8"
#define BLYNK_YELLOW    "#ED9D00"
#define BLYNK_RED       "#D3435C"
#define BLYNK_DARK_BLUE "#5F7CD8"

// Indicate which board we are using
//#define NODEMCU
#define WEMOS

#include <BlynkSimpleEsp8266.h>
#include <WiFiManager.h>          //https://github.com/tzapu/WiFiManager
#include <ArduinoOTA.h>  // For OTA
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <WidgetRTC.h>
#include <PID_v1.h>
#include <EEPROM.h>

#define EEPROM_SALT 12667
typedef struct {
  char    blynkToken[33]  = "";
  double  tempSetpoint    = 10;
  double  Kp              = 2;
  double  Ki              = 5;
  double  Kd              = 1;
  int     WindowSizeMax   = 5000;
  int     WindowSizeMin   = 0;
  int     PIDMode         = AUTOMATIC;
  int     PIDDirection    = REVERSE;
  int     PIDProportional = P_ON_E;
  int     salt            = EEPROM_SALT;
} DefaultSettings;
DefaultSettings settings;

#define OLED_RESET -1
Adafruit_SSD1306 display(OLED_RESET);

#ifdef MYDEBUG
  #define MYDEBUG_PRINT(...) Serial.print(__VA_ARGS__)
  #define MYDEBUG_PRINTLN(...) Serial.println(__VA_ARGS__)
#else
  #define MYDEBUG_PRINT(...)
  #define MYDEBUG_PRINTLN(...)
#endif

// This is the data pin we will use for the temperature sensor
#define ONE_WIRE_BUS D6

#include <DallasTemperature.h>
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

// Pin on the NODEMCU we will use for controlling the relay
#define RELAY_BUS1 D7

#ifdef NODEMCU
#define LED_BUS D0
#endif

#ifdef WEMOS
#define LED_BUS 2
#endif

// select wich pin will trigger the configuraton portal when set to LOW
// ESP-01 users please note: the only pins available (0 and 2), are shared 
// with the bootloader, so always set them HIGH at power-up.  For the NodeMCU boards
// this is the flash button...very convenient
// NOTE: for the LinkSprite board this is D8 and there is no button on board
#define TRIGGER_PIN 0

// The extra parameters to be configured (can be either global or just in the setup)
// After connecting, parameter.getValue() will get you the configured value
// id/name placeholder/prompt default length
WiFiManagerParameter custom_token("token", "blynk token", settings.blynkToken, sizeof(settings.blynkToken));

int read_fails = 0; // will increment each time a bad read occurs
int report_fails = 0; // will increment if we didn't get a good reading in the report period
bool report_good = false; // When we report back to blynk we will reset this to false and each good read will set to true

int V4_Index = 0;  // 0 = Version, 1 = Hostname, 2 = IP Address, 3 = SSID, 4 = BSSID, 5 = Auth Token

// Real time clock
WidgetRTC rtc;

// Timer functions
BlynkTimer timer;
// Timer IDs
int timerID_ReadSensor;
int timerID_ReportSensor;
int timerID_CheckConnection;
int timerID_ResetESP;
int timerID_CheckForReset;
int timerID_ResetSensor;
int timerID_runPID;
int timerID_oledDisplay;
int timerID_EEPROMCheck;

// Timer Durations
#define timer_ReadSensor  1000L // 1 Second
#define timer_ReportSensor  1000L // 1 Second
#define timer_CheckConnection  10000L  // 10 Seconds
#define timer_ResetESP  60000L  // 1 minute
#define timer_CheckForReset  1000L // 1 second
#define timer_ResetSensor 300000L // if the sensor hasn't had a good reading in 5 minutes reset
#define timer_runPID 100L // .1 seconds
#define timer_oledDisplay 2000L  // refresh the display every 2 seconds 
#define timer_EEPROMCheck 60000L // 1 minute

// PID Section
double tempC;
double Output;
PID myPID(&tempC, &Output, &settings.tempSetpoint, settings.Kp, settings.Ki, settings.Kd, settings.PIDDirection);

unsigned long windowStartTime;

//callback notifying us of the need to save config
void saveConfigCallback () {
  MYDEBUG_PRINTLN("Config has changed, let's save it");
  //read updated parameters
  strcpy(settings.blynkToken, custom_token.getValue());
  SaveFlash();
}

bool ReadFlash()
{
   // Read the EEPROM and if salt is good return true
  EEPROM.begin(512);
  EEPROM.get(0, settings);
  EEPROM.end();
  if (settings.salt == EEPROM_SALT) return true;
  else return false;
}

void SaveFlash()
{
  EEPROM.begin(512);
  EEPROM.put(0, settings);
  EEPROM.end();
}

void InitFlash()
{
    MYDEBUG_PRINTLN("Invalid settings in EEPROM, settings defaults");
    DefaultSettings defaults;
    settings = defaults;
    EEPROM.begin(512);
    EEPROM.put(0, settings);
    EEPROM.end();
}

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  delay(1000);
  MYDEBUG_PRINTLN();
  
  // Print out version info
  MYDEBUG_PRINT("Version: ");
  MYDEBUG_PRINTLN(VERSION);
  
  pinMode(LED_BUS, OUTPUT); //Declare Pin mode for LED flasher

  pinMode(RELAY_BUS1, OUTPUT); //Declare Pin mode for Relay Module
  digitalWrite(RELAY_BUS1,HIGH);

  pinMode(ONE_WIRE_BUS, INPUT_PULLUP);  // eliminates need for 4.7k resistor in DS18B20 CCT
  sensors.begin();
  // Set resolution to 11 bits
  // Bits Res     Time
  // 9    0.5C    93.75ms
  // 10   0.25C   197.5ms
  // 11   0.125C  375ms
  // 12   0.0625C 750ms
  sensors.setResolution(11);
  // Request temperature in sync mode first
  sensors.requestTemperatures();
  sensors.setWaitForConversion(false);
  
  // by default, we'll generate the high voltage from the 3.3v line internally
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 0x3D (for the 128x64)
  // init done
  
  // Show image buffer on the display hardware.
  // Since the buffer is intialized with an Adafruit splashscreen
  // internally, this will display the splashscreen.
  display.display();
  // Clear the buffer.
  display.clearDisplay();
  display.setTextColor(WHITE);
  display.println("System Starting...");
  display.println("");
  display.println(VERSION);
  display.println("");
  
  // If json is not good the only thing we should do is recreate it.
  if (!ReadFlash())
  {
    // Flash isn't setup
    InitFlash();  
  }
  
  //WiFiManager
  //Local intialization. Once its business is done, there is no need to keep it around
  WiFiManager wifiManager;
 
  //set config save notify callback
  wifiManager.setSaveConfigCallback(saveConfigCallback);
  
  wifiManager.addParameter(&custom_token);
      
  // If the blynkToken is not yet configured there is no point connecting to whatever
  // was configured for wifi.
  if (settings.blynkToken == "") 
  {
    wifiManager.resetSettings();
    display.println("Blynk not configured");
    display.println("");
    display.print("AP:");
    display.println(" ESP" + String(ESP.getChipId()));
    display.display();
  }
  else 
  {
    wifiManager.setTimeout(120);
    display.println("Connecting to WiFi...");
    display.display();
  }

  //tries to connect to last known settings
  //if it does not connect it starts an access point 
  //and goes into a blocking loop awaiting configuration
  if (!wifiManager.autoConnect()) {
    MYDEBUG_PRINTLN("failed to connect");
    // If we timeout here it is because we have a configuration but it didn't connect
    // We don't need to do anything as it should connect later when wifi is available
    // or we didn't configure it correctly and will have to push the flash button
    
  }
  else
  {
    // We did connect
    MYDEBUG_PRINT("local ip: ");
    MYDEBUG_PRINTLN(WiFi.localIP());
  }

  MYDEBUG_PRINT("Blynk Token: ");
  MYDEBUG_PRINTLN(settings.blynkToken);

  // Configure Blynk with the valid stored auth token or the new one just configured
  Blynk.config(settings.blynkToken);

  // Other Time library functions can be used, like:
  //   timeStatus(), setSyncInterval(interval)...
  // Read more: http://www.pjrc.com/teensy/td_libs_Time.html
  setSyncInterval(10 * 60); // Sync interval in seconds (10 minutes)
  
  // ArduinoOTA.setHostname("Wemos D1 Mini");  // For OTA - Use your own device identifying name
  ArduinoOTA.begin();  // For OTA

  // Start up timer routines
  timerID_ReadSensor = timer.setInterval(timer_ReadSensor, ReadSensor);
  timerID_ReportSensor = timer.setInterval(timer_ReportSensor, ReportSensor);
  timerID_CheckConnection = timer.setInterval(timer_CheckConnection, CheckConnection);  
  timerID_ResetESP = timer.setInterval(timer_ResetESP, ResetESP);
  timerID_CheckForReset = timer.setInterval(timer_CheckForReset, CheckForReset);
  timerID_ResetSensor = timer.setInterval(timer_ResetSensor, ResetSensor);
  timerID_runPID = timer.setInterval(timer_runPID, runPID);
  timerID_oledDisplay = timer.setInterval(timer_oledDisplay, oledDisplay);
  timerID_EEPROMCheck = timer.setInterval(timer_EEPROMCheck, EEPROMCheck);

  // Initialize PID parameters
  windowStartTime = millis();

  //tell the PID to range between 0 and the full window size
  myPID.SetOutputLimits(settings.WindowSizeMin, settings.WindowSizeMax);

  //turn the PID on
  myPID.SetMode(settings.PIDMode);

  myPID.SetSampleTime(timer_runPID);
}

void loop() {
  // put your main code here, to run repeatedly:

  if (WiFi.status() == WL_CONNECTED) 
  {
    Blynk.run();
    ArduinoOTA.handle();  // For OTA
  }
  timer.run();
}

void ReadSensor() {
  
  // Round the temp to one decimal point
  tempC = sensors.getTempCByIndex(0);
  
  // Round to one decimal
  //tempC = round(tempC * 10.0)/10.0;
  
  if (tempC != -127.0)
  {
    // Reset the ResetSensor timer
    timer.restartTimer(timerID_ResetSensor);
    report_good = true;
  }
  else
  {
    read_fails = read_fails + 1;
  }

  // Start the next async temperature read
  sensors.requestTemperatures();
}

void ReportSensor() {
  // Report the data back to Blynk
  if (WiFi.status() == WL_CONNECTED)
  {
     if (tempC < 127)
    {
      // Only report good data
      Blynk.virtualWrite(V0, tempC);
      Blynk.virtualWrite(V2, settings.tempSetpoint);
      Blynk.virtualWrite(V16, Output);
    }
    
  }
     
  // Debug code to verify the sensor is working, output data to the serial port
  MYDEBUG_PRINTLN("");
  MYDEBUG_PRINT("wifi status: ");
  MYDEBUG_PRINTLN(WiFi.status());
  MYDEBUG_PRINT("blynk status: ");
  MYDEBUG_PRINTLN(Blynk.connected());
  MYDEBUG_PRINT("Temp: ");
  MYDEBUG_PRINT(tempC);
  MYDEBUG_PRINTLN(" *C");
        
  //Strobe LED
  digitalWrite(LED_BUS, LOW);   //Turn the LED on
  delay(50);
  digitalWrite(LED_BUS, HIGH);   //Turn the LED off
}

void CheckConnection() {
  // Check to see if wifi is in a connected state and we are connected to Blynk
  if (WiFi.status() == WL_CONNECTED)
  {
    if (Blynk.connected())
    {
      // Reset the ResetESP timer
      timer.restartTimer(timerID_ResetESP);
    }
    else
    {
      MYDEBUG_PRINTLN("Blynk not connected, reconnect.");
      bool result = Blynk.connect();
    }
  }
}

void ResetESP() {
  // We have not been connected to WiFi for timer_ResetESP duration, restart the ESP
  MYDEBUG_PRINTLN("wifi connect has failed, restarting...");
  //reset and try again, or maybe put it to deep sleep
  while(1) ESP.reset();
  delay(5000);
}

void ResetSensor() {
  // We have not had a good reading in 5 minutes from the DHT22, restart the ESP
  MYDEBUG_PRINTLN("DS18B20 is not responding, reset ESP");
  //reset and try again, or maybe put it to deep sleep
  while(1) ESP.reset();
  delay(5000);
}

void CheckForReset() {
  // is configuration reset requested?
  if ( digitalRead(TRIGGER_PIN) == LOW ) {
        
    MYDEBUG_PRINTLN("Reset Settings, waiting for restart");
 
    delay(3000);
    //reset and try again, or maybe put it to deep sleep
    while(1) ESP.reset();
    delay(5000);
    
  }
}

void runPID() {
  // Check if the temp is above the setpoint, if so then call for cooling
  // If we are in manual mode then just eject.  Relay will be controlled by user.
  if (myPID.GetMode() == MANUAL) return;
  myPID.Compute();
  MYDEBUG_PRINT(Output);
  /************************************************
   * turn the output pin on/off based on pid output
   ************************************************/
  if (millis() - windowStartTime > settings.WindowSizeMax)
  { //time to shift the Relay Window
    windowStartTime += settings.WindowSizeMax;
  }
  if (Output < millis() - windowStartTime) 
  {
    // No output required.  Relay is enabled on LOW so set to HIGH.
    digitalWrite(RELAY_BUS1, HIGH);
    MYDEBUG_PRINTLN(" Relay DISABLED");
    if (WiFi.status() == WL_CONNECTED)
    {
      Blynk.virtualWrite(V1, LOW);
    }
  }
  else
  {
    // Output required.  Relay is enabled on LOW so set to LOW.
    digitalWrite(RELAY_BUS1, LOW);
    MYDEBUG_PRINTLN(" Relay ENABLED");
    if (WiFi.status() == WL_CONNECTED)
    {
      Blynk.virtualWrite(V1, HIGH);
    }
  }
}

BLYNK_READ(V3)
{
 if (WiFi.status() == WL_CONNECTED)
  {
    Blynk.virtualWrite(V3, WiFi.RSSI());
    MYDEBUG_PRINTLN("Sending RSSI");
  }
}

BLYNK_READ(V4)
{
 if (WiFi.status() == WL_CONNECTED)
  {
    if (V4_Index == 0)
    {
      Blynk.setProperty(V4, "label", "Software Version");
      Blynk.virtualWrite(V4, VERSION);
      MYDEBUG_PRINTLN("Sending Version");
      V4_Index = 1;
    }
    else if (V4_Index == 1)
    {
      Blynk.setProperty(V4, "label", "Hostname");
      Blynk.virtualWrite(V4, WiFi.hostname());
      MYDEBUG_PRINTLN("Sending Hostname");
      V4_Index = 2;
    }
    else if (V4_Index ==2)
    {
      Blynk.setProperty(V4, "label", "IP Address");
      Blynk.virtualWrite(V4, WiFi.localIP().toString());
      MYDEBUG_PRINTLN("Sending IP Address");
      V4_Index = 3;
    }
    else if (V4_Index ==3)
    {
      Blynk.setProperty(V4, "label", "SSID");
      Blynk.virtualWrite(V4, WiFi.SSID());
      MYDEBUG_PRINTLN("Sending SSID");
      V4_Index = 4;
    }
    else if (V4_Index ==4)
    {
      Blynk.setProperty(V4, "label", "BSSID");
      Blynk.virtualWrite(V4, WiFi.BSSIDstr());
      MYDEBUG_PRINTLN("Sending BSSID");
      V4_Index = 5;
    }
    else if (V4_Index ==5)
    {
      Blynk.setProperty(V4, "label", "AUTH TOKEN");
      Blynk.virtualWrite(V4, settings.blynkToken);
      MYDEBUG_PRINTLN("Sending Auth Token");
      V4_Index = 0;
    }
  } 
}

BLYNK_READ(V5)
{
 if (WiFi.status() == WL_CONNECTED)
  {
    
    Blynk.virtualWrite(V5, read_fails);
    MYDEBUG_PRINTLN("Sending Read Fails");
  } 
}

BLYNK_READ(V6)
{
 if (WiFi.status() == WL_CONNECTED)
  {
    Blynk.virtualWrite(V6, report_fails);
    MYDEBUG_PRINTLN("Sending Report Fails");
  } 
}

BLYNK_WRITE(V7)
{
  settings.tempSetpoint = param.asDouble(); // Get value as double
  MYDEBUG_PRINT("Received setpoint: ");
  MYDEBUG_PRINT(settings.tempSetpoint);
  MYDEBUG_PRINTLN(" *C");
}

BLYNK_WRITE(V8)
{
  MYDEBUG_PRINT("Received PIDmode: ");
  if (param.asInt() == 0)
  {
    MYDEBUG_PRINTLN("0 AUTOMATIC");
    settings.PIDMode = 0;
    myPID.SetMode(AUTOMATIC);
  }
  else
  {
    settings.PIDMode = 1;
    MYDEBUG_PRINTLN("1 MANUAL");
    myPID.SetMode(MANUAL);
    // Turn the relay off if switching to manual mode, user can now control
    digitalWrite(RELAY_BUS1, HIGH);
    if (WiFi.status() == WL_CONNECTED)
    {
      Blynk.virtualWrite(V1, LOW);
    }
  }
}

BLYNK_WRITE(V9)
{
  MYDEBUG_PRINT("Received PIDDirection: ");
  if (param.asInt() == 0)
  {
    MYDEBUG_PRINTLN("0 DIRECT");
    settings.PIDDirection = 0;
    myPID.SetControllerDirection(DIRECT);
  }
  else
  {
    MYDEBUG_PRINTLN("1 REVERSE");
    settings.PIDDirection = 1;
    myPID.SetControllerDirection(REVERSE);
  }
}

BLYNK_WRITE(V10)
{
  settings.WindowSizeMax = param.asInt() * 1000; // Get value as integer
  myPID.SetOutputLimits(settings.WindowSizeMin, settings.WindowSizeMax);
  MYDEBUG_PRINT("Received WindowSizeMax: ");
  MYDEBUG_PRINTLN(settings.WindowSizeMax);
}

BLYNK_WRITE(V11)
{
  settings.WindowSizeMin = param.asInt() * 1000; // Get value as integer
  myPID.SetOutputLimits(settings.WindowSizeMin, settings.WindowSizeMax);
  MYDEBUG_PRINT("Received WindowSizeMin: ");
  MYDEBUG_PRINTLN(settings.WindowSizeMin);
}

BLYNK_WRITE(V12)
{
  MYDEBUG_PRINT("Received PIDProportionalMode: ");
  if (param.asInt() == 0)
  {
    MYDEBUG_PRINTLN("0 P_ON_E");
    settings.PIDProportional = P_ON_E;
  }
  else
  {
    MYDEBUG_PRINTLN("1 P_ON_M");
    settings.PIDProportional = P_ON_M;
  }
  myPID.SetTunings(settings.Kp, settings.Ki, settings.Kd, settings.PIDProportional); 
}

BLYNK_WRITE(V13)
{
  settings.Kp = param.asDouble(); // Get value as Double
  myPID.SetTunings(settings.Kp, settings.Ki, settings.Kd, settings.PIDProportional);
  MYDEBUG_PRINT("Received Kp: ");
  MYDEBUG_PRINTLN(settings.Kp);
}

BLYNK_WRITE(V14)
{
  settings.Ki = param.asDouble(); // Get value as Double
  myPID.SetTunings(settings.Kp, settings.Ki, settings.Kd, settings.PIDProportional);
  MYDEBUG_PRINT("Received Ki: ");
  MYDEBUG_PRINTLN(settings.Ki);
}

BLYNK_WRITE(V15)
{
  settings.Kd = param.asDouble(); // Get value as Double
  myPID.SetTunings(settings.Kp, settings.Ki, settings.Kd, settings.PIDProportional);
  MYDEBUG_PRINT("Received Kd: ");
  MYDEBUG_PRINTLN(settings.Kd);
}

BLYNK_CONNECTED() {
    Blynk.syncAll();
    // Synchronize time on connection
    rtc.begin();
}

// Update info on the display

void oledDisplay()
{
  int bars;
//  int bars = map(RSSI,-80,-44,1,6); // this method doesn't refelct the Bars well
  // simple if then to set the number of bars
  int RSSI = WiFi.RSSI();
  
  if (RSSI > -55) { 
    bars = 5;
  } else if (RSSI < -55 & RSSI > -65) {
    bars = 4;
  } else if (RSSI < -65 & RSSI > -70) {
    bars = 3;
  } else if (RSSI < -70 & RSSI > -78) {
    bars = 2;
  } else if (RSSI < -78 & RSSI > -82) {
    bars = 1;
  } else {
    bars = 0;
  }

  display.clearDisplay();
// Do some simple loop math to draw rectangles as the bars
// This will occupy the top left of screen (0,0) to (21,10)
  for (int b=0; b <= bars; b++) {
    display.fillRect(6+(b*3),10-(b*2),2,b*2,WHITE); 
  }
  // Draw the antenna symbol
  display.drawTriangle(0,0,10,0,5,5,WHITE);
  display.fillRect(5,0,1,10,WHITE);

  // Build up a 12H time string
  String currentTime = String() + ((hour()%12) < 10 ? " " : "") + (hour()%12)+ ':' + (minute() < 10 ? "0" : "") + minute();

  // right justify time on first line.  Time hh:mm am
  display.setCursor(80,0);
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.print(currentTime);
  display.print((hour() > 12 ? " PM" : " AM"));
  // on the second line display the setpoint and whether HEAT is being called
  display.setCursor(80,8);
  display.print(String() + (settings.tempSetpoint < 10 ? " " : "") + String(settings.tempSetpoint,0) + "C");
  
  // Move to a half character height below the yellow area of the OLED
  display.setCursor(0,16);
  display.setTextSize(1);
  display.print("Temp");
  display.setCursor(0,28);
  display.setTextSize(3);
  display.print(String(tempC,0));
  display.setTextSize(2);
  display.print("C");
  display.setCursor(80,28);
  display.setTextSize(3);
    
  // Move to the bottom line of the display and print out hostname and last 4 bytes of auth token
  display.setTextSize(1);
  display.setCursor(0,56);
  display.print(WiFi.hostname());
  //auth token is right justified
  display.setCursor(104,56);
  display.print(String()+settings.blynkToken[28]+settings.blynkToken[29]+settings.blynkToken[30]+settings.blynkToken[31]);
  display.display();
}

void EEPROMCheck()
{
  // Check to see if the EEPROM copy needs to be updated
  DefaultSettings EEPROMsettings;
  EEPROM.begin(512);
  EEPROM.get(0, EEPROMsettings);
  EEPROM.end();
  if ((settings.tempSetpoint == EEPROMsettings.tempSetpoint) && (settings.Kp == EEPROMsettings.Kp) && (settings.Ki == EEPROMsettings.Ki) 
      && (settings.Kd == EEPROMsettings.Kd) && (settings.WindowSizeMax == EEPROMsettings.WindowSizeMax) 
      && (settings.WindowSizeMin == EEPROMsettings.WindowSizeMin) && (settings.PIDMode == EEPROMsettings.PIDMode)
      && (settings.PIDDirection == EEPROMsettings.PIDDirection) && (settings.PIDProportional == EEPROMsettings.PIDProportional))
  {
    MYDEBUG_PRINTLN("EEPROM is up to date");
  }
  else
  {
    MYDEBUG_PRINTLN("EEPROM not current, updating...");
    EEPROM.begin(512);
    EEPROM.put(0, settings);
    EEPROM.end();
  }
}
>
1 Like

Hmm… I assume the problem is with V7, right?
The setpoint is assigned here:

BLYNK_WRITE(V7)
{
  settings.tempSetpoint = param.asDouble(); // Get value as double
  MYDEBUG_PRINT("Received setpoint: ");
  MYDEBUG_PRINT(settings.tempSetpoint);
  MYDEBUG_PRINTLN(" *C");
}

And then send to App here:

void ReportSensor() {
  // Report the data back to Blynk
  if (WiFi.status() == WL_CONNECTED)
  {
     if (tempC < 127)
    {
      // Only report good data
      Blynk.virtualWrite(V0, tempC);
      Blynk.virtualWrite(V2, settings.tempSetpoint);   <-- here
...

Then I see no reason, the slider behaves as it does. :thinking:
Have you tried with integer instead of double? the temperature alone is well within it… Anyway it shouldn’t make a difference here. Might it be a bug? @BlynkAndroidDev , @Dmitriy ??

By the way: nice code :slight_smile: What is this? A PWM controlled thermostat?

@marvin7, correct the issue is with V7 but it also exists occasionally when I adjust the Kp, Ki and Kd parameters. I wanted to reliably chart the setpoint so I use a different virtual pin to make that work.

I have not tried using an integer as the input as the PID library requires a double but likely not the issue as you have stated.

Yes, this is a temperature controller for an industrial (beer brewing) process but the code is completely generic at the moment.

Word of caution at the moment…the OLED routines are from a thermostat program I have and haven’t been completely ported over for this purpose…they may not work correctly…

I haven’t focused at display part - irrelevant for the issue. I wonder if timing could somehow influence the slider. I mean, you use timers independently from app events, and that is of course clear. But when operations of reading/writing collide (still - how close in time is to “collide”?) it might (well?? it shouldn’t!) produce some issues. As noted earlier - I have never had troubles with sliders except once, when it was (partly) my fault. No need to explain details, but it WAS a timing issue. The difference in your case is obvious to me, but I’m unable to find anything else, so…

Thanks @marvin7 for having a look. Pretty sure I am not doing anything wrong with the code. The sliders are only sending data so timing shouldn’t play a part. Sounds like a bug to me but I am always open to someone indicating otherwise. Bottom line is I will have to find a different way to control the process.

Just a WAG but have you completely removed that slider and replaced it? Just in case there is something corrupted in the project settings.

I think I figured out the bug. I can now cause it 100% of the time. When the blynk app is running with a slider on the screen and then the screen times out or if I hit the button on the phone to sleep the screen and then wake the screen and then touch the slider and it jumps to 0. Completely repeatable.

If the screen does not time out it works fine 100% of the time. So the issue is when phone comes out of screen saver mode and blynk is the displayed app.

I hope this makes sense.

1 Like

Have you done what I suggested? There was issues in the past, and you might need to simply refresh things to reset it?

Perhaps even clone the whole project, delete and restore from QR

Just a side note, are you using PID with a relay?

Then all you can do is to try @Gunner’s suggestion. If it won’t help, you are left with a pray to devs for fixing it (Or use either terminal or step widget for temp input)