Call function() with Segmented Switch

Help will be appreciated
I’m using an ESP32 to control a pool pump and its solar panel. I want to use the segmented switch to be able to run the pool pump in manual (on/off) and in auto (3 cases). The on/off is working but I can’t seem to get the auto to work from the segmented switch. I know the automated function works as the segmented switch is a functionallity I have added later as I found it required.
The temperature sensors refered to in the code is OneWire/Dallas DS18B20 sensors managed in another function and declared as GLOBAL’s

My proposed code looks like this (sections of it)

BLYNK_WRITE(V14) {
      switch (param.asInt()) {
    case 1:  //AUTO Selected
    //Start pump when the solar temp. sensor is above PARAM1
  if (tempSensor2>=(tempSensor4+startDT)){
    led1.on();
    digitalWrite(pumpRunLED,HIGH);
    digitalWrite(pumpStart,HIGH);
    }
    //Stop pump when the differential temperature is below PARAM2 & pumpOff timer has expired
  if ((tempSensor2-tempSensor4)<stopDT){
    led1.off();
    digitalWrite(pumpRunLED,LOW);
    digitalWrite(pumpStart,LOW);
    }
    break;
    
    case 2:  // ON Selected
    led1.on();
    digitalWrite(pumpRunLED,HIGH);
    digitalWrite(pumpStart,HIGH);
     break;
    
    case 3:  // OFF Selected
    led1.off();
    digitalWrite(pumpRunLED,LOW);
    digitalWrite(pumpStart,LOW);
    break;
    
    }
    }

BLYNK_CONNECTED()
    {
    Blynk.syncVirtual(V14);
    }

void pumpautoStart(void){

  if (tempSensor2>=(tempSensor4+startDT)){
    led1.on();
    digitalWrite(pumpRunLED,HIGH);
    digitalWrite(pumpStart,HIGH);
    }
    //Stop pump when the differential temperature is below PARAM2 & pumpOff timer has expired
  if ((tempSensor2-tempSensor4)<stopDT){
    led1.off();
    digitalWrite(pumpRunLED,LOW);
    digitalWrite(pumpStart,LOW);
    }
}

Kind regards
Jesper

When I’m trying to debug stuff like this, I throw in lots of serial print commands to show the value of the various variables (and if necessary the results of things like this:
(tempSensor2-tempSensor4)<stopDT)
to double-check that I’m seeing the expected values.

It’s impossible to tell from your code snippets, but is pumpautoStart() being called with a timer?
If it needs to be run when the value of V14 changes, then maybe call it from your case statements?

Pete.

Hi Pete
The idea is to call the pumpautoStart() from case1 but it seams like the function only runs once when the segmented switch changes state. I would like the function to keep updating when case1 is selected.

Kr
Jesper

That’s not how BLYNK_WRITE(vPin) works.

The BLYNK_WRITE(vPin) callback is in effect the equivalent of a hardware interrupt on a physical pin - it runs once when it detects a change in state of a virtual pin.

If you want a loop then use a BlynkTimer.

Pete.

Pete, I don’t understand how a timer would make my automation work.
The intension is when the system is in auto the pump should start the when the solar panel is 7 degC higher than the pool temperature and stop the pump when the differential temperature (solar panel vs pool temperature) is less than 0.3 DegC.
As I understand a timer then it runs a task at a set time and stops it agan at a set time. Unfortunately this is not how I get the most heat into the pool as if it starts raining or we get hail then the solar panel quickly gets cold and starts cooling the water instead.

Kr
Jesper

P.S. I can post the entire sketch if required but it’s 240 lines

No, if you use a BlynkTimer (a modified version of the SimpleTimer library) then you can create a non-blocking loop.
I’d set-up a BlynkTimer that ran let’s say every second, which calls a function that evaluates your logical conditions and takes the appropriate action. This may well be your pumpautoStart function, but it’s difficult to say.

There is a good example of how to use a BlynkTimer in this way here:
http://help.blynk.cc/getting-started-library-auth-token-code-examples/blynk-basics/keep-your-void-loop-clean

Pete.

Pete, I understand what you are saying but I find it impossible for me to do from reading the link and the other link to Arduino Playground/SimpleTimer. I see that I could do with this timer:

int setInterval(long d, timer_callback f)

Call function f every d milliseconds. The callback function must be declared as void f() .

void repeatMe() { // do something } timerId = timer.setInterval(1000, repeatMe);

but how to incorporate this into my needs I cannot figure out.
Kr
Jesper

I cant really explain further without seeing your full code.

Pete.

Full code

//Pool monitoring & automation 

#define BLYNK_PRINT Serial

#include <WiFi.h>
#include <WiFiClient.h>
#include <BlynkSimpleEsp32.h>

#include <OneWire.h>
#include <DallasTemperature.h>

    // Data wire from DS18B20 sensors "OneWire" on pin 4 on the ESP32
#define ONE_WIRE_BUS 4

//Timing
unsigned long previousMillis = 0;
const long interval = 1000;          //Interval to read

    //Pump variables
    int pumpRunLED=12; //LED Indicator for pump running (works on pump pressure)
    int pumpStart=27; //Output pin for pump start relay
    float startDT; //PARAM1 Differential between pool temp and solarpanel out temp managed from Blynk App
    BLYNK_WRITE(V15){
      startDT = param.asFloat();
    }
    float stopDT; //PARAM2 Differential to stop pump when the diff temp is below thi set value from Blynk App
    BLYNK_WRITE(V16){
      stopDT = param.asFloat();
    }
    
    //Variables for ESP32 supply voltage measurement from DC-DC Converter (24VDC-5.5VDC)
    int VHealthy=25; //LED output pin 5 Volt healthy
    int vPin=33; // 5V pin
    int voltValue=0.0; //Variable to store value in 
    float VDC=0.0; //Float voltage value
    
    //Variables for Pump Pressure Monitoring
    int highDPin=13;  //Warning light for high discharge pressure across sand filter
    int pressPin=34; //4-20mA pin via voltage drop resistor
    int voltIn = 0.0;      //Analog Input
    float OutputValue = 0.0;    //Voltage In after voltage divider
    float Press = 0.0;       //Actual Pressure after calculation
    float pumpPressHigh=0.7; //Parameter for pump pressure too high
    float pumpPressLow=0.6; // Parameter for pump pressure OK
     
    // Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
    OneWire oneWire(ONE_WIRE_BUS);

    // Pass our oneWire reference to Dallas Temperature.
    DallasTemperature sensors(&oneWire);

    uint8_t sensor1[8] = { 0x28, 0xC6, 0xB5, 0x56, 0xB5, 0x01, 0x3C, 0x2F  };
    uint8_t sensor2[8] = { 0x28, 0xC9, 0xD0, 0x56, 0xB5, 0x01, 0x3C, 0xC8  };
    uint8_t sensor3[8] = { 0x28, 0xD0, 0x9F, 0x56, 0xB5, 0x01, 0x3C, 0x83  };
    uint8_t sensor4[8] = { 0x28, 0x61, 0x0D, 0x56, 0xB5, 0x01, 0x3C, 0x87  };
    uint8_t sensor5[8] = { 0x28, 0x35, 0xD0, 0x56, 0xB5, 0x01, 0x3C, 0xC7  };
    float tempSensor1, tempSensor2, tempSensor3, tempSensor4, tempSensor5;

    // You should get Auth Token in the Blynk App.
    // Go to the Project Settings (nut icon).
    char auth[] = "XXXXXXXXXXXXXXXXXXX";

    // Your WiFi credentials.
    // Set password to "" for open networks.
    char ssid[] = "xxxxxxxxxxxxxx";
    char pass[] = "xxxxxxxxxxx";

    BlynkTimer timer;

    WidgetLED led1(V11); //pumprunLED
    WidgetLED led2(V12); //pump filter high DP LED
    WidgetLED led3(V13); //Vhealthy LED
    
    BLYNK_WRITE(V14) {
      switch (param.asInt()) {
    case 1:  //AUTO Selected
    //Start pump when the solar temp. sensor is above PARAM1
    pumpautoStart();
    break;
    
    case 2:  // ON Selected
    led1.on();
    digitalWrite(pumpRunLED,HIGH);
    digitalWrite(pumpStart,HIGH);
     break;
    
    case 3:  // OFF Selected
    led1.off();
    digitalWrite(pumpRunLED,LOW);
    digitalWrite(pumpStart,LOW);
    break;
    
    }
    }
    
    // This function sends Arduino's up time every second to Virtual Pin (5).
    // In the app, Widget's reading frequency should be set to PUSH. This means
    // that you define how often to send data to Blynk App.

void myTimerEvent()
    {
    // You can send any value at any time.
    // Please don't send more that 10 values per second.
    Blynk.virtualWrite(V5, millis() / 1000);
    }

BLYNK_CONNECTED()
    {
    Blynk.syncVirtual(V14);
    Blynk.syncVirtual(V15);
    Blynk.syncVirtual(V16);
    }

void setup()
    {
    // Debug console
    Serial.begin(115200);

    sensors.begin();

    pinMode(pressPin,INPUT); // Input from 4-20mA Pressure Transmitter via a 165ohm voltage drop resistor (3.3/0.020=165ohm)
    pinMode(vPin,INPUT); // Input via voltage devider 5V=2.73VDC
    pinMode(pumpStart, OUTPUT); // Output to relay for starting pump when the conditions are met
    pinMode(VHealthy,OUTPUT); //LED "green" for ESP32 Voltage supply is healthy
    pinMode(highDPin,OUTPUT); //LED "yellow" for high DP across sand filter
    pinMode(pumpRunLED,OUTPUT); //LED Inditation for pump running
  
    Blynk.begin(auth, ssid, pass);
    // You can also specify server:
    //Blynk.begin(auth, ssid, pass, "blynk-cloud.com", 80);
    //Blynk.begin(auth, ssid, pass, IPAddress(192,168,1,100), 8080);

    // Setup a function to be called every second
    timer.setInterval(1000L, myTimerEvent);

    Serial.println("Connecting to ");
    Serial.println(ssid);

    //connect to your local wi-fi network
    WiFi.begin(ssid, pass);

    //check wi-fi is connected to wi-fi network
    while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.print(".");
    }
    Serial.println("");
    Serial.println("WiFi connected..!");
    Serial.print("Got IP: ");  Serial.println(WiFi.localIP());
  }

void Temp(void){

unsigned long currentMillis = millis();
    if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;

  //Update sensors in loop for the if statements to work
    sensors.requestTemperatures();  // Send the command to get temperatures
    tempSensor1 = sensors.getTempC(sensor1); // Reads the values of Solar panel inlet temperature
    tempSensor2 = sensors.getTempC(sensor2); // Reads the values of Solar panel outlet temperature
    tempSensor3 = sensors.getTempC(sensor3); // Reads the values of air temperature
    tempSensor4 = sensors.getTempC(sensor4); // Reads the values of pool temperature
    tempSensor5 = sensors.getTempC(sensor5); // Reads the PCB temperature
}
}

void pumpautoStart(void){

  if (tempSensor2>=(tempSensor4+startDT)){
    led1.on();
    digitalWrite(pumpRunLED,HIGH);
    digitalWrite(pumpStart,HIGH);
    }
    //Stop pump when the differential temperature is below PARAM2 & pumpOff timer has expired
  if ((tempSensor2-tempSensor4)<stopDT){
    led1.off();
    digitalWrite(pumpRunLED,LOW);
    digitalWrite(pumpStart,LOW);
    }
}

void Pressure(void){
  //Pressure Transmitter
    voltIn=analogRead(pressPin); //Read analog values
    OutputValue = map(voltIn,650,4095,0,4000); //Convert input to an actual pressure reading using a 4-20ma pressure transmitter remember the digits on the converted value to have decimals
    Press=OutputValue/1000;
    //Press = OutputValue; // Using a voltage drop resistor and the formula to work out the resistor: VoltIn(max 3.3V)/max current "20ma" (0.020A)= 165ohm 
  
  if (Press>pumpPressHigh){
    led2.on();
    digitalWrite(highDPin,HIGH); //Sets Yellow warning LED on
    }
  if (Press<pumpPressLow){
    led2.off();
    digitalWrite(highDPin,LOW); //Sets Yellow warning LED off
    }
    }

void Voltage(void){ 

    //5VDC Supply from DC-DC Converter via a voltage devider (max 3.3V = 820ohm 
    voltValue=analogRead(vPin);
    VDC = map(voltValue,0,4095,0,6000);
    VDC=VDC/1000;

  if (VDC>5.0 && VDC<6.2){
    led3.on();
    digitalWrite(VHealthy,HIGH);  //Sets green voltage healthy LED on)
    }
  if (VDC<5.0 || VDC>6.2){
    led3.off();
    digitalWrite(VHealthy,LOW);  //Sets green voltage NOT healthy LED off)
    }
    }
  
void loop(){
    Blynk.run();
    timer.run(); // Initiates BlynkTimer

    //Functions
    Temp();
    Pressure();
    Voltage();

    //Blynk variables 
    Blynk.virtualWrite(V1, tempSensor1); //Solar panel inlet temperature
    Blynk.virtualWrite(V2, tempSensor2); //Solar panel outlet temperature
    Blynk.virtualWrite(V3, tempSensor3); //Ambient temperature
    Blynk.virtualWrite(V4, tempSensor4); //Pool temperature
    Blynk.virtualWrite(V6, Press); //Pump Discharge pressure
    Blynk.virtualWrite(V7, VDC); //5VDC supply voltage variable
    Blynk.virtualWrite(V8, tempSensor5); //PCB Temp

    Serial.print("startDT: "); Serial.print(startDT); Serial.print(", stopDT: ");Serial.println(stopDT);

    }

Okay, well you’ll never get this to work with alongside Blynk with a void loop that takes temperature, pressure and voltage readings - and more importantly does Blynk.virtualWrites in the void loop, for the reasons outlined in the “keep your void loop clean” document.

I’d suggest moving the Blynk.virtualWrites into the functions that generate the readings. For example, put this line:

Blynk.virtualWrite(V7, VDC); //5VDC supply voltage variable

into your Voltage() function.

Then, create a new function which calls the Temp(), Pressure() and Voltage() functions, and call this with a timer. Like this:

void call_my_functions()
{
    // Functions to be called....
    Temp();
    Pressure();
    Voltage();
}

and add a timer to void loop() that takes readings every 5 seconds…

timer.setInterval(5000L, call_my_functions);

You could shorten the timing of the timer if you wish, but start at 5 seconds for now.

Take-out all of the previousMillis versus currentMillis stuff from your Temp() function, as its not needed with the BlynkTimer.

Now, if you want your pumpautoStart() function to run as a loop then add a timer for this as well…

timer.setInterval(5000L, pumpautoStart);

Once again, keep the timer at 5 seconds for testing, then shorten the timing as necessary.

Pete.

Hi, Thank you I had thourght about moving these to the right places but it didn’t work out for me when I tried, I must have done something wrong. Now it compiles ok’

Question, If I want to call the pumpautoStart() function can’t I just simply put in in here like this:

void call_my_functions(){
    Temp();
    Pressure();
    Voltage();
    pumpautoStart();
}

Jesper

Yes, that’s a good way to do it.

Pete.

1 Like

Pete, wouldn’t the update interval be the Blynk timer (1000) plus the setInterval (5000)=6000ms?

void myTimerEvent(){
    // You can send any value at any time.
    // Please don't send more that 10 values per second.
    Blynk.virtualWrite(V5, millis() / 1000);
    }
&
void loop(){
    Blynk.run();
    timer.run();
    timer.setInterval(5000L, call_my_functions);
    }

Or what does the Blynk Timer do?

Jesper

This line belongs in the void setup

Each timer object (‘timer’ in this case) can have up to 16 independent timers which call different functions on different time intervals.

You will have two timers declared in your void setup:

timer.setInterval(1000L, myTimerEvent);
timer.setInterval(5000L, call_my_functions);

The first one runs every second and sends the uptime in seconds to the Blynk app
The second one takes the temperature, humidity and voltage readings and they send their respective results to the Blynk app.

The timer.run() command services the timer object, and each time it’s serviced it checks to see if any of the timers that have been declared need to be kicked-off again.

In a similar way, the Blynk.run() command services the Blynk library, which does a handshake with the server to acknowledge that it’s still alive, and to see if anything has changed on the app. If it finds a change - for example the state of a widget attached to a virtual pin has changed - then it will fire the appropriate callback function (BLYNK_WRITE(V14) for example).

On that note, I notice that you have a BLYNK_CONNECTED() command which syncs V14, V15 and V16.
All this does is whenever the device connects or reconnects to the Blynk server it causes the BLYNK_WRITE(V14), BLYNK_WRITE(V15) and BLYNK_WRITE(V16) callbacks to fire.

The only issue is that you don’t have BLYNK_WRITE(V15) or BLYNK_WRITE(V16) callbacks in your code (at least not yet), so these tow commands in BLYNK_CONNECTED() are redundant.

Pete.

Pete, sorry I don’t understand what you mean about the callbacks that are not in place for V15 & V16

Jesper

Sorry, I missed the BLYNK_WRITE(V15) and BLYNK_WRITE(V16) in your code, they were hiding in plain sight :grinning:

For easy debugging though, you might want to group them all together in consecutive numerical order - it will save you time later.

Pete.

1 Like

Like this:

  BLYNK_WRITE(V14){
      switch (param.asInt()) {
    case 1:  //AUTO Selected
    //Start pump when the solar temp. sensor is above PARAM1
    pumpautoStart();
    break;
    
    case 2:  // ON Selected
    led1.on();
    digitalWrite(pumpRunLED,HIGH);
    digitalWrite(pumpStart,HIGH);
     break;
    
    case 3:  // OFF Selected
    led1.off();
    digitalWrite(pumpRunLED,LOW);
    digitalWrite(pumpStart,LOW);
    break;
    }
  }  

  BLYNK_WRITE(V15){
    startDT = param.asFloat();
  }
  BLYNK_WRITE(V16){
    stopDT = param.asFloat();
  }

BLYNK_CONNECTED()
    {
    Blynk.syncVirtual(V14); //Segmented Switch "Auto/On/Off"
    Blynk.syncVirtual(V15); //PARAM1 start pump
    Blynk.syncVirtual(V16); //PARAM2 stop pump
    }
1 Like

Much better!

Pete.

Pete, Now I just need to get verified if the auto function works when I get back home on Saturday.

Thank you very much for your help, I really appreciate this.

Kind regards
Jesper

1 Like

No problem. Pick this conversation back up again if it doesn’t work, and I’ll dig a bit deeper into your logic and see if I can understand it a bit better.

If it does work then let me know anyway and I’ll mark the topic as solved (that doesn’t close it, just makes it easier when people are searching and looking for similar issues that have been solved).

Pete.

1 Like