I have built a device to control a winemaking process and I can connect and send variable updates from the Android app to the ESP32 controller.
I am however concerned that time is spent sending from device to cloud and cloud to device even when nothing changes.
I see on the app widgets some have setting to send only on release, but seems that others sync on every Virtual Pin Write or Virtual Pin Read.
Is there a smart way to only send/read update only of there is a change to one or more values?
Should I set a flag if a value changes but this would need tracking of old value and new value for each parameter and seems complex?
Appreciate any guidance as all are more experienced than I am.
#define BLYNK_TEMPLATE_ID
#define BLYNK_TEMPLATE_NAME
#define BLYNK_FIRMWARE_VERSION "0.1.0"
#define BLYNK_PRINT Serial
//#define BLYNK_DEBUG
#define APP_DEBUG
#include "BlynkEdgent.h"
#include <FS.h>
#include <ezTime.h>
#include <TFT_eWidget.h> // Widget library
#include <SPI.h>
#include <TFT_eSPI.h> // Hardware-specific library
#include "Free_Fonts.h" // Include the header file attached to this sketch
TFT_eSPI tft = TFT_eSPI(); // Invoke custom library
Timezone local;
// This function creates the timer object. It's part of Blynk library
BlynkTimer timer;
#define CALIBRATION_FILE "/TouchCalData1"
bool REPEAT_CAL = false;
// Hardware definitions
#define LED_PIN 22 // On board LED
// Software Definitions
#define BUTTON_W 120
#define BUTTON_H 40
#define BUTTON_PAD 20
BLYNK_CONNECTED() { // Send requests for internal data when connected
Blynk.sendInternal("utc", "time"); // Unix timestamp (with msecs)
Blynk.sendInternal("utc", "tz_rule"); // POSIX TZ rule
}
// Receive UTC data from cloud
BLYNK_WRITE(InternalPinUTC) {
String cmd = param[0].asStr();
if (cmd == "time") {
const uint64_t utc_time = param[1].asLongLong();
UTC.setTime(utc_time / 1000, utc_time % 1000);
Serial.print("Unix time (UTC): ");
Serial.println(utc_time);
} else if (cmd == "tz_rule") {
String tz_rule = param[1].asStr();
local.setPosix(tz_rule);
Serial.print("POSIX TZ rule: ");
Serial.println(tz_rule);
}
}
/*------------------------------------------------------------------------------------------------------------------------------*/
// Cloud variables
String DateTimeCurrent; // VO --> Current date and time
byte CycleFrequency[4]; // V1 --> Cycle frequency # times per day 1-24
float TempCurrent = 73.2; // V2 --> Current temp
float TimerCountdown; // V3 --> hh:mm:ss remaining in cycle
String CycleReason = "Power"; // V4 --> Reason for punch, Powere, Auto, Manual, Temp
byte CycleTimeDown[4]; // V5 --> Seconds down 10 - 255
byte CycleTimeUp[4]; // V6 --> Seconds up 10 - 255
byte NumCyclesTime[4]; // V7 --> Number of cycles when Time triggered
byte NumCyclesTemp[4]; // V8 --> Number of cycles when Temp triggered
bool Mode; // V9 --> 0 = Manual, 1 = Auto
int Phase; // V10 -> Enumerated Phase code 0,1,2,3
bool Shake; // V11 -> 0 = No Shake, 1 = Shake
int Pressure; // V12 -> Pressue psi 0-255
bool State; // V13 -> 0 = paused, 1 = Running
byte TempDwell[4]; // V14 -> 0-255 minutes delay between Temp punch events
float TempMax; // V15 -> Recorded Max Temp until cleared
byte TempThreshold[4]; // V16 -> Trigger point to start temp plunge
bool Reset; // V17 -> Reset max temp
/*------------------------------------------------------------------------------------------------------------------------------*/
// Working Variables
int ScreenNo = 1; // 1 = home, 2 = config
float Timer; // temporary to test and will removed.
unsigned long Time1; // temporary to test and will removed.
unsigned long Time2; // temporary to test and will removed.
ButtonWidget btn_Mode = ButtonWidget(&tft); // Auto-Manual
ButtonWidget btn_State = ButtonWidget(&tft); // Running-Ready-Paused
ButtonWidget btn_Profile = ButtonWidget(&tft); // Innoc-Lag-Active-Finish
ButtonWidget btn_Config = ButtonWidget(&tft); // Calibrate-Profile update
ButtonWidget btn_Increase = ButtonWidget(&tft); // Can this be a generic increase for selected button???
ButtonWidget btn_Decrease = ButtonWidget(&tft);
ButtonWidget btn_Calibrate = ButtonWidget(&tft); // Calibrate screen touch
// Create an array of button instances to use in display loops
ButtonWidget *btn[] = { &btn_Mode, &btn_State, &btn_Profile, &btn_Config, &btn_Increase, &btn_Decrease, &btn_Calibrate };
uint8_t buttonCount = sizeof(btn) / sizeof(btn[0]); // How many buttons
const char *Profile[] = { "Innoc", "Active", "Lag", "Finish" }; // Button names
//int Pn = 0;
// Get parameters from platform
// No need to get V0, V2, V3, V4, V12, V15 as they are only sent to client
BLYNK_WRITE(V1) {
CycleFrequency[Phase] = param.asInt();
DrawScreen();
}
BLYNK_WRITE(V5) {
CycleTimeDown[Phase] = param.asInt();
DrawScreen();
}
BLYNK_WRITE(V6) {
CycleTimeUp[Phase] = param.asInt();
DrawScreen();
}
BLYNK_WRITE(V7) {
NumCyclesTime[Phase] = param.asInt();
}
BLYNK_WRITE(V8) {
NumCyclesTemp[Phase] = param.asInt();
}
BLYNK_WRITE(V9) {
Mode = param.asInt();
}
BLYNK_WRITE(V10) { // Get enumerated Phase from Cloud
Phase = param.asInt(); // enumerated value for 0,1,2,3
Serial.println(Phase);
}
BLYNK_WRITE(V11) {
Shake = param.asInt();
}
BLYNK_WRITE(V13) {
State = param.asInt();
}
BLYNK_WRITE(V14) {
TempDwell[Phase] = param.asInt();
}
BLYNK_WRITE(V16) {
TempThreshold[Phase] = param.asInt();
}
BLYNK_WRITE(V17) { // Get Reset from Cloud
Reset = param.asInt();
if (Reset == 1) {
TimerCountdown = 120.0;
TempCurrent = 69.0;
}
}
void setup() {
Serial.begin(115200); // Start Serial
timer.setInterval(1000L, secTimer); // Set up second event timer
timer.setInterval(60000L, minTimer); // Set up minute event timer
while (!Serial) { ; } // Wait incase serial is not ready
tft.begin(); // Start screen
tft.setRotation(1); // Set screen as Landscape
tft.fillScreen(TFT_BLACK); // Clear SCreen
tft.setTextColor(TFT_GREEN, TFT_BLACK); // Set text color
touch_calibrate(); // Check and calibrate the touch screen if required and retrieve the scaling factors
BlynkEdgent.begin(); // Start Blynk Agent
initButtons(); // Initialize buttons
Serial.print("Buttons = ");
Serial.println(buttonCount);
}
void loop() {
BlynkEdgent.run(); // runs Blynk Agent
timer.run(); // runs BlynkTimer
waitForSync(); // Wait until time has been set by eztime
static uint32_t scanTime = millis();
uint16_t t_x = 9999, t_y = 9999; // To store default unused touch coordinates
// Scan keys every 50ms at most -- CHange to Timer interupt
if (millis() - scanTime >= 50) {
// Pressed will be set true if there is a valid touch on the screen
bool pressed = tft.getTouch(&t_x, &t_y);
scanTime = millis();
if (ScreenNo = 1) {
for (uint8_t b = 0; b < buttonCount; b++) {
if (pressed) {
if (btn[b]->contains(t_x, t_y)) {
btn[b]->press(true);
btn[b]->pressAction();
Serial.println(ScreenNo);
}
} else {
btn[b]->press(false);
btn[b]->releaseAction();
}
}
}
}
//-------------------------------------------------------------------------
// Other stuff
// Get Temp
// Get pressure
// Plunge if time or temp
}
void secTimer() { // This function describes what will happen with each timer tick - Send all necessary data to BLYNK cloud
Blynk.beginGroup(); // Send data to cloud
Blynk.virtualWrite(V1, CycleFrequency[Phase]);
Blynk.virtualWrite(V16, TempThreshold[Phase]);
Blynk.virtualWrite(V5, CycleTimeDown[Phase]);
Blynk.virtualWrite(V6, CycleTimeUp[Phase]);
Blynk.virtualWrite(V7, NumCyclesTime[Phase]);
Blynk.virtualWrite(V8, NumCyclesTemp[Phase]);
Blynk.virtualWrite(V14, TempDwell[Phase]);
Blynk.virtualWrite(V2, TempCurrent);
Blynk.virtualWrite(V3, TimerCountdown);
Blynk.virtualWrite(V9, Mode);
Blynk.virtualWrite(V10, Phase);
Blynk.virtualWrite(V11, Shake);
Blynk.virtualWrite(V13, State);
Blynk.virtualWrite(V17, Reset);
Blynk.endGroup();
// Update the time display on the TFT screen
DrawScreen();
}
void minTimer() {
// if (minuteChanged()) WriteToSomeDisplay(UTC.dateTime("H:i")); https://github.com/ropg/ezTime?tab=readme-ov-file#working-with-time-values
DateTimeCurrent = local.dateTime("D h:i a "); // Get the current formatted time string
Blynk.virtualWrite(V0, DateTimeCurrent); // Current day-date-time
Blynk.virtualWrite(V4, CycleReason); // Cycle Reason
Blynk.virtualWrite(V15, TempMax); // Max temp
Blynk.virtualWrite(V12, Pressure); // Current pressure
}
More display/logic functions but no Blynk functions
Network Data