setProperty crashes Blynk app on iOS10

Not sure what’s changed, but everything seems to have stabilized. No crashes, resets or otherwise aberrant behavior in over a week. :facepunch:

I spoke too soon. I’m getting the random slider widget resets again.

@Eugene @Dmitriy

Okay… after a bit more testing, I’ve pinpointed the trigger for the slider reset bug.

I use the setPreperty command to control two Blynk widgets: an LED and a gauge. Both are set to WHITE in their app settings. Under certain conditions, I turn them both RED, using the setProperty command. This seems to go off without a hitch. It’s only when I turn them back to WHITE that an unrelated slider widget is reset to its minimum. This is particularly odd, since the slider is not one of the widgets being manipulated by the setProperty command.

The relevant code in my Dec 16 posting, above. Currently on Blynk library 0.4.3 and iOS app 2.8.1.

Yep, sounds strange. I see some pieces of your code here and there, could you please post the whole sketch, if it is not a secret of course :slight_smile:

@Eugene You asked for it. :wink:

/**************************************************************************** 
 *  ThermoX v0.15 HVAC control for a "2-pipe" radiator system.
 *  
 *  Compares readings from a DHT11 temperature sensor with desired temperature
 *  from the Blynk application, and runs the fan unit as necessary to heat or 
 *  cool.  Hysteresis levels for both Summer and Winter are independently 
 *  adjustable from 2 to 6 degrees. The temperature sensor readings can be 
 *  offset up or down by up to 5 degrees. All settings are saved to EEPROM, and 
 *  automatically reloaded on startup.
 *  
 *  "Home" setting is triggered by IFTTT iOS location channel, and results in an
 *  action on the Maker channel. The Maker channel parameters are as follows:
 *       URL: http://blynk-cloud.com:8080/YOUR_TOKEN/pin/V31
 *       Method: PUT
 *       Content Type: application/json
 *       Body: ["1"]    
 *  "Away" mode requires an identical IFTTT recipe, but with
 *       Body: ["0"]
 *  
 *  Added color coding (red/blue) for heating and cooling modes to dashboard widgets.
 *  
 *  Added IFTTT / Amazon Echo integration for operating with voice commands. Uses 
 *  the IFTTT Maker Channel in the same way as above, but with an Amazon Alexa voice 
 *  trigger. To manually run the fan, use the following Maker Channel parameters: 
 *       URL: http://blynk-cloud.com:8080/YOUR_TOKEN/pin/V6
 *       Method: PUT
 *       Content Type: application/json
 *       Body: ["1"]    
 *  Make identical recipes (now called applets) for Temperature Up and Temperature 
 *  Down, substituting Body values of ["2"] and ["3"], repsectively.  
 *  
 *  Added a press-and-hold requirement to enter the settings menu, as well as
 *  a Menu timeout and reset after a period of inactivity. 
 *  Added manual overrides to force system run or halt, independent of other factors.
 *  Added a diagnostic mode that outputs temperature readings to the SETTINGS widget.
 *  Extended lower limit of temperature correction to -10 degrees.
 *  Fixed arithmetic bug that was causing Blynk to show ESP as "offline"
 *  
 *  WiFi connection is now simplified with Tapzu's WiFiManager. Wifi automatically
 *  reconnects to last working credentials. If the last SSID is unavailable, it
 *  creates an access point ("BlynkAutoConnect"). Connect any wifi device to the
 *  access point, and a captive portal pop up to receive new wifi credentials.
 *  
 *  The hardware is minimal: an ESP-01, a single relay on GPIO 0, and a DHT11
 *  temperature sensor on GPIO 2.
 *  
*****************************************************************************
*/
#include <ESP8266WiFi.h>  //https://github.com/esp8266/Arduino
#include <BlynkSimpleEsp8266.h>
#include <ESP8266WebServer.h>
#include <DNSServer.h>
#include <WiFiManager.h>  //https://github.com/tzapu/WiFiManager
#include <SimpleTimer.h>
#include "DHT.h"
#include <EEPROM.h>

#define UpdateFrequency 10000 //How often a new temperature will be read
#define MenuTimeOut 7000 //Menu timeout from inactivity
#define LongPress 650 //How long SETTINGS button needs to be pressed to enter menu
#define RelayPin 2


#define BLYNK_BLUE      "#04C0F8"
#define BLYNK_RED       "#D3435C"
#define BLYNK_WHITE     "#FFFFFF"

DHT dht(0,DHT11); //Initialize the sensor. Use pin 0. Sensor type is DHT11.

// Timer for temperature updates
SimpleTimer timer;

//WiFi and Blynk connection variables
char auth[] = "YOUR_TOKEN"; // Blynk token "YourAuthToken"

//Thermostat variables
int TempDes = 70;             //Desired temperature setting
int PreviousTempDes;
int TempAct = 70;             //Actual temperature, as measured by the DHT11 sensor
int BadRead = 0;              //Counts consecutive failed readings of the DHT11 sensor
float LastRead = 70; 

// Preference variables
int Hysteresis_W = 2;         //Summer and Winter hysteresis levels
int Hysteresis_S = 2;
int TempCorrection = 0;       //Used to adjust readings, if the sensor needs calibration

// Current condition variables
boolean Winter = true; 
boolean Home = true;
boolean ManualRun = false;    // used to run fan, overriding thermostat algorithm
boolean ManualStop = false;   // used to stop fan, overriding thermostat algorithm
boolean DigitalTemp = false;  // used to show temperature in SETTINGS value widget
int MenuItem = 0;             // Settings menu selection variable
long buttonRelease;           // time button was released
long buttonPress;             // time button was last pressed
boolean ButtonDown = false;   // Settings button state (pressed = true)
boolean FanState = 0;         // is the fan on or off?
String Response = "";         // Text output to SETTINGS value widget

String myHostname = "ThermoX";

void setup() {
  
  // Create an access point if no wifi credentials are stored
  WiFi.hostname(myHostname);
  WiFiManager wifi;
  wifi.autoConnect("ThermoX"); 
  Blynk.config(auth);
  
  dht.begin(); //Start temperature sensor
  delay(1500);

  //Initialize the fan relay. Mine is "off" when the relay is set HIGH.
  pinMode(RelayPin,OUTPUT); 
  digitalWrite(RelayPin,HIGH);
 
  Serial.begin(115200);
  delay(10);
  
  //Load any saved settings from the EEPROM
  EEPROM.begin(20);  
  Serial.println(F("STARTUP : LOADING SETTINGS FROM MEMORY"));
  Serial.println(F(""));
  GetPresets();

  PreviousTempDes = TempDes; 
  
  MenuReset();

  timer.setInterval(UpdateFrequency, TempUpdate); // Update temp reading and relay state
  timer.setInterval(200, ButtonCheck);
}


// Main loop
void loop() {
  Blynk.run();
  timer.run();
}

// Checks for long press condition on SETTINGS button
void ButtonCheck(){
  if (ButtonDown){
    // Enter or exit the SETTINGS menu, if it was a long press
    if (millis() - buttonPress > LongPress){ 
      if (MenuItem == 0){
        NextMenuItem(); // Enter the SETTINGS menu
      }
      else MenuReset(); // Exit the SETTINGS menu 

      ButtonDown = false; // Prevent repeat triggering
    }
  }
}


// This is the decision algorithm for turning the HVAC on and off
void TempUpdate (){
  OtherUpdates(); //Refeshes dashboard information

  float ReadF = dht.readTemperature(true); //Get a new reading from the temp sensor
    
  if (isnan(ReadF)) {
    Serial.println(F("Failed to read from DHT sensor!"));
    BadRead++;
    return;
  }

  //To compensate for some instability in the DHT11, the corrected temperature is
  //averaged with previous read, and any change is limited to 1 degree at a time. 
  else   { 
    int TempAvg = int((ReadF + LastRead + (2 * TempCorrection))/2);
    if (TempAvg > TempAct){
      TempAct += 1;
    }
    if (TempAvg < TempAct){
      TempAct -= 1;
    }

    LastRead = ReadF;
    BadRead = 0;        // Reset counter for failed sensor reads
  }
  
  Blynk.virtualWrite(V0,TempAct); //Report the corrected temperature in app
  Serial.print("Actual temperature: ");
  Serial.println(TempAct);

  if (DigitalTemp){ //Report the temperature to the SETTINGS widget
    Blynk.virtualWrite(V10,"-----------------------");
    delay(50);
    Blynk.virtualWrite(V10,String("TEMPERATURE: ") + TempAct);
  }

  // Decision algorithm for running HVAC
  if (!ManualRun && !ManualStop){   // Make sure it's not in one of the manual modes
    // If I'm home, run the algorithm
    if (Home){
      if (Winter){
        //If I'm home, it's Winter, and the temp is too low, turn the relay ON
        if (TempAct < TempDes){
          FanState = 1;
          Fan();
        }
        //Turn it off when the space is heated to the desired temp + a few degrees
        else if ((TempAct >= (TempDes + Hysteresis_W)) && FanState) {
          FanState = 0;
          Fan();
        }
      }
      else if (!Winter){
        //If I'm home, it's Summer, and the temp is too high, turn the relay ON
        if (TempAct > TempDes){
          FanState = 1;
          Fan();
        }
        //Turn it off when the space is cooled to the desired temp - a few degrees
        else if ((TempAct <= (TempDes - Hysteresis_S)) && FanState){
          FanState = 0;
          Fan();
        }
     }
    }
    // If I'm not home, turn the relay OFF
    else {
      FanState = 0;
      Fan();
    }
  }
}


//Match temp gauge to slider in Blynk app 
BLYNK_WRITE(V3){
  TempDes = param.asInt();
  Blynk.virtualWrite(V1,TempDes);
}

//Get location (home or away) from the IFTTT iOS location and Maker channels
BLYNK_WRITE(V31)
{   
  Home = param.asInt();
  
  if (Home){ //Turn the HOME LED widget on or off
    Blynk.virtualWrite(V29,1023);
  }
  else Blynk.virtualWrite(V29,0);
}

   
// Dashboard SETTINGS button. Press-and-hold to enter menu. Short press for next item.
BLYNK_WRITE(V4) {
  // Check for a button press
  ButtonDown = param.asInt();
  if (ButtonDown){ 
     buttonPress = millis();
     DigitalTemp = false;
   }
    // check for button release
    else {
      buttonRelease = millis();
      if (buttonRelease - buttonPress < LongPress){  // It was a short press.
        if (MenuItem == 0){
        MenuReset(); // Remind user to hold 2 seconds to enter menu
        }
      else NextMenuItem(); // Advance to next menu item
      }
   }
}


//Cycles through the Settings Menu in the Labeled Value widget
void NextMenuItem(){
  
  MenuItem += 1;
  if (MenuItem > 8){
    MenuItem = 1;
  }
    
  switch(MenuItem){
      case 1:
        if (ManualRun){
          Response = "END MANUAL RUN?";
        }
        else{
          Response = "RUN MANUALLY?";
        }
        break;

      case 2:
        if (ManualStop){
          Response = "END SYSTEM HALT?";
        }
        else{
          Response = "HALT SYSTEM?";
        }
        break;
        
     case 3:
      if (Home){
        Response = "LOCATION: HOME";
      }
      else Response = "LOCATION: AWAY";
      break;


    case 4:
      if (Winter){
        Response = "MODE : WINTER";
      }
      else Response = "MODE : SUMMER";
      break;

    case 5:
      if (Winter){
        Response = "HYSTERESIS: ";
        Response +=  Hysteresis_W;
        Response += " DEG";   
      }
      else{
        Response = "HYSTERESIS: ";
        Response += Hysteresis_S;
        Response += " DEG";
      }
      break;

    case 6:
      Response = "TEMP CORRECTION: ";
      Response += TempCorrection;
      Response += " DEGREES";
      break;
      
    case 7:
      Response = "DIAGNOSTIC MODE?";
      break;

    case 8:
      Response = "CLEAR WIFI SETTINGS?";
      break;

    case 9:
       Response = "RESET ALL DEFAULTS?";
       break;
  }
  Blynk.virtualWrite(V10,Response);
}


//Dashboard MODIFY button. Executes change of selected menu item 
BLYNK_WRITE(V5){
  
  buttonRelease = millis(); //Resets menu timeout for inactivity
  
  if ((MenuItem > 0) && (param.asInt())){
    switch(MenuItem){

        //Forced on
      case 1:
        if (ManualRun){
          ManualRun = false;
          Response = "RUN MANUALLY?";
        }
        else{
          ManualRun = true;
          ManualStop = false;
          FanState = 1;
          Fan();
          Response = "MANUAL RUN: ON";
        }   
        break;

        //Forced halt
      case 2:
        if (ManualStop){
          ManualStop = false;
          Response = "HALT SYSTEM?";
        }
        else {
          ManualStop = true;
          ManualRun = false;
          FanState = 0;
          Fan();
          Response = "SYSTEM HALTED";
        }
        break;

         //Change location manually
      case 3:
        if (Home){
          Home = false;
          Response = "LOCATION : AWAY";
        }
        else {
          Home = true;
          Response = "LOCATION : HOME";
        }
        break;
        
      //Change season
      case 4:
        if (Winter){
          Response = "MODE : SUMMER";
          Winter = false;
          EEPROM.write(4,0);
          EEPROM.commit();
        }
        else {
          Response = "MODE : WINTER";
          Winter = true;
          EEPROM.write(4,1);
          EEPROM.commit();
        } 
        break;
        
      //Change hysteresis level of currently selected season
      case 5:
        if (Winter){
          Hysteresis_W += 1;
          if (Hysteresis_W > 6){
            Hysteresis_W = 1;
          }
          EEPROM.write(1,(Hysteresis_W));
          EEPROM.commit();
          Response = "WINTER HYSTERESIS: ";
          Response += Hysteresis_W;
          Response += " DEG";
        }
        else{
          Hysteresis_S += 1;
          if (Hysteresis_S > 6){
            Hysteresis_S = 1;
          }
          EEPROM.write(2,(Hysteresis_S));
          EEPROM.commit();
          Response = "SUMMER HYSTERESIS: ";
          Response += Hysteresis_S;
          Response += " DEG";
          }
        break;

      // Correct faulty DHT11 readings
      case 6:
        TempCorrection +=1;
        if (TempCorrection > 5){
          TempCorrection = -10;
        }
        EEPROM.write(0,(TempCorrection + 10));
        EEPROM.commit();
        Response = "TEMPERATURE CORRECTION: ";
        Response += TempCorrection;
        Response += " DEG";
        break;

       // Send temperature readings to the SETTINGS value widget
      case 7:
        if (!DigitalTemp){
          Response = "ENTERING DIAGNOSTIC MODE";
          DigitalTemp = true;
          MenuItem = 0; //Prevents menu reset
          delay(400);
        }
        else {
          Response = ("DIAGNOSTIC MODE?");
          DigitalTemp = false;
        }
        break;
        

      //Clear stored SSID and password
      case 8:
        Response = "ERASING WIFI CREDENTIALS";
        WiFi.begin("FakeSSID","FakePW"); //replace current WiFi credentials with fake ones
        delay(1000);
        ESP.restart();
        break;

      //Clear current temperature settings
      case 9:
        Response = "All settings reset to default!";
        Winter = true;
        Hysteresis_W = 2;
        Hysteresis_S = 2;
        break;
    }
    Blynk.virtualWrite(V10, Response);
  }
}

// Receives commands from IFTTT Maker Channel via the Amazon Echo. 
// Pin V6 is not actually associated with a Blynk dashboard widget.
BLYNK_WRITE(V6){
  int AlexaCommand = param.asInt();

  switch(AlexaCommand){
    // Turn manual running on / off
    case 1:
      Serial.println("Manual run");
      if (ManualRun){
          ManualRun = false;
        }
      else{
        ManualRun = true;
        ManualStop = false;
        FanState = 1;
        Fan();
      }   
      break;
    // Increase desired temperature by 2 degrees
    case 2: 
      Serial.println("Raise temperature 2 degrees.");
      TempDes += 2;
      break;
    // Decrease desired temperature by 2 degrees
    case 3:
      Serial.println("Lower temperature 2 degrees.");
      TempDes -= 2;
      break;
  }
}


// Turn the HVAC on or off
void Fan(){

  // Set the proper color for the Desired Temp gauge and ON/OFF LED
  //(red = heating, blue = cooling, white gauge or LED off = within desired range)
  if (Winter && FanState){
      Blynk.setProperty(V0, "color", BLYNK_RED);
      Blynk.setProperty(V7, "color", BLYNK_RED);
    }
    else if (!Winter && FanState){
      Blynk.setProperty(V0, "color", BLYNK_BLUE);
      Blynk.setProperty(V7, "color", BLYNK_BLUE);
    }
    else{
      Blynk.setProperty(V0, "color", BLYNK_WHITE);
    }
    
  digitalWrite(RelayPin,!FanState); // Relay turns fan on with LOW input, off with HIGH
  Blynk.virtualWrite(V7,FanState * 1023);// fan "ON" LED on dashboard
  Serial.print(F("Fan state: "));
  Serial.println(FanState);
}


// Reset the Menu at startup or after timing out from inactivity
void MenuReset(){
  MenuItem = 0;
  Blynk.virtualWrite(V10, String("-----------------------"));
  delay(50);
  Blynk.virtualWrite(V10, String("HOLD 2 SEC TO ENTER/EXIT MENU"));
}


// Updates dashboard information on the Blynk app
void OtherUpdates(){
  Blynk.virtualWrite(V29,Home * 1023);  // Update "home" LED on dashboard
  Blynk.virtualWrite(V1,TempDes);       //Update desired temp on the dashboard
  
  //Reset the Settings Menu if there's been no activity for a while
   if (MenuItem > 0 && (millis() - buttonRelease > MenuTimeOut)){
     MenuReset();
   }
   
   // Notify when the temperature sensor fails repeatedly, and turn off the fan.
   if (BadRead > 10){
     Blynk.virtualWrite(V10, String("<<< SENSOR MALFUNCTION >>>"));
     BadRead = 0;
     if (!ManualRun){ //Manual mode supersedes a malfunction condition
      FanState = 0;
      Fan();
     }
   }
   
   if (TempDes != PreviousTempDes){   //update the EEPROM if desired temperature had changed.
    EEPROM.write(3,TempDes);
    EEPROM.commit();
    Serial.print(F("New desired temperature saved: "));
    Serial.println(TempDes);
    PreviousTempDes = TempDes;  
   }
}

//Retrieves saved values from EEPROM
void GetPresets(){
  TempCorrection = EEPROM.read(0);
  if ((TempCorrection < 0) || (TempCorrection > 15)){
    TempCorrection = 0;
    Serial.println(F("No saved temperature correction."));
  }
  else{
    TempCorrection -= 10; // 10 was added at EEPROM save to account for negative values
    Serial.print(F("Temperature correction: "));
    Serial.print(TempCorrection);
    Serial.println(F(" degrees."));      
  }

  Winter = EEPROM.read(4);
  Hysteresis_W = EEPROM.read(1);
  Hysteresis_S = EEPROM.read(2);

  if ((Hysteresis_W < 2) || (Hysteresis_W > 6)){
      Hysteresis_W = 2;
  }
  if ((Hysteresis_S < 2) || (Hysteresis_S > 6)){
      Hysteresis_S = 2;
  }
  
  if (Winter){
    Serial.println(F("Season setting: Winter / heating"));
    Serial.print(F("Winter hysteresis: "));
    Serial.print(Hysteresis_W);
    Serial.println(F(" degrees."));   
  }
  else {
    Serial.println(F("Season setting: Summer / cooling"));
    Serial.print(F("Summer hysteresis: "));
    Serial.print(Hysteresis_S);
    Serial.println(F(" degrees."));      
  } 
 
  TempDes = EEPROM.read(3);
  if ((TempDes < 50) || (TempDes > 80)){
    TempDes = 70;
    Serial.println(F("No saved temperature setting."));
  }
  else {
    Serial.print(F("Desired temperature: "));
    Serial.print(TempDes);
    Serial.println(F(" degrees."));   
  }
  Serial.println("");
}

Dashboard assignments:

Tab 1 >
V0 = desired temperature gauge
V1 = actual temperature gauge
V3 = set temperature slider

Tab 2 >
V10 = settings value display
V4 = settings menu button
V5 = menu modify button
V7 = fan on indicator LED
V29 = home indicator LED

I don’t see any pitfalls. Look like we have to wait for 2.8.2 update (should be soon, being reviewed by apple at the moment). The update has “send logs” feature. After update, right after you next time catch this “slider reset” thing, just send me the logs. We’ll see then what it says.

Hi!
Is the “color setProperty” crash fixed in 2.8.2? I´m trying to set the color of a Gauge-widget depending on a value. As soon as Blynk.setProperty(V1, “color”, BLYNK_RED); is triggered the app stop refreshing all widgets. If I stop and restart the project the values are updated again, until the setProperty is triggered again. Any clues?

This is a bug. Fixed in upcoming 2.8.3. Sorry for inconvenience.

@Eugene; Does this bug also affect the responsiveness of the app? Seems like my app is sluggish, not responding to all touch inputs. It does not appear to be the phone or the screen.

Thanks

@mpo881 No. Does it reproduce? Sounds like your app got freeze…

Yes, it is similar to the other report. My virtual leds are not updating unless I stop the app and then restart it. Once I restart it, I notice I have to tap the feature I want several times to have anything happen. Once I get past that, it seems to work ok. But yes, it is repeatable.

Thank you

Thanks for reply, no worries, glad you confirmed it! :slight_smile:

@Eugene It’s only been 2 days since I updated, but 2.8.3 seems to have resolved the slider reset bug.

Hi Guys,

Glad I found this as I have the exact same problem with the slider widget resetting to zero all the time, but only on an android device. It works fine on my iphone 6 with ios10 and blynk ver 2.8.6, so I guess that rules out my code.

Any ideas ?

Cheers

Kev

Hi Guys!

Sorry for my stupid question but where is the relationship between V5 and V6 ? I want to use this two timers as two different time zone for heating pump.

Best,
Mateusz