Hi Blynk Team,
I’m currently using Blynk to monitor pH values with a line graph. I’m encountering an issue: while the live data view on both mobile and web consoles appears as expected, I’m seeing unexpected spikes when switching to 1-hour or 6-hour recorded modes on the web console. This issue does not occur on the mobile app, where the data remains consistent without spikes.
Here are the specifics of my setup:
- Hardware: ESP32, pH Sensor via RS485 (Modbus Communication), AC input pulse to denote start and end times.
I have attached some images for reference. Could you please provide a solution for this discrepancy?
Finally this is my code snippet:
// Blynk credentials
#define BLYNK_TEMPLATE_ID "----------------"
#define BLYNK_TEMPLATE_NAME "--------------------"
#define BLYNK_AUTH_TOKEN "------------------------------------"
// Include necessary libraries
#include <WiFi.h>
#include <BlynkSimpleEsp32.h>
#include <time.h>
#include <Wire.h>
#include <Adafruit_MCP23X17.h>
// MCP23017 GPIO Expander object
Adafruit_MCP23X17 mcp;
// Arrays to hold sensor data
String Temp[2];
String PH_R[4];
uint8_t value[4];
String result;
String PH_result;
// New WiFi credentials
const char* ssid = "---------------";
const char* password = "----------------";
// Define the pins for TX and RX
#define RS485_TX 17
#define RS485_RX 16
// Initialize HardwareSerial for RS485 communication
HardwareSerial RS485Serial(1);
// Timezone settings for India Kolkata GMT +5:30
const char* ntpServer = "pool.ntp.org";
const long gmtOffset_sec = 5.5 * 3600;
const int daylightOffset_sec = 0;
void setup() {
// Start Serial communication
Serial.begin(115200);
// Initialize the MCP23X17 GPIO expander
mcp.begin_I2C(0x21); // Use your MCP23017 address here
// Initialize RS485 communication
RS485Serial.begin(9600, SERIAL_8N1, RS485_RX, RS485_TX);
// Set pin 8 of MCP23017 as INPUT
mcp.pinMode(8, INPUT);
// Initialize WiFi and Blynk
WiFi.begin(ssid, password);
Blynk.begin(BLYNK_AUTH_TOKEN, ssid, password);
// Wait for WiFi connection
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
}
Serial.println(WiFi.localIP());
// Initialize NTP
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
}
void loop() {
// Run Blynk to handle communication
Blynk.run();
// Send predefined messages over RS485
sendRS485Message_PH();
delay(10); // Small delay
sendRS485Message_Temperature();
// Check for incoming RS485 messages
if (RS485Serial.available()) {
receiveRS485Message();
}
// Schedule deep sleep
scheduleDeepSleep();
}
void sendRS485Message_PH() {
// Predefined message to request pH data
byte PhCmd[] = { 0x01, 0x04, 0x00, 0x00, 0x00, 0x02, 0x71, 0xCB };
RS485Serial.write(PhCmd, sizeof(PhCmd));
delay(10); // Small delay to ensure message is sent
}
void sendRS485Message_Temperature() {
// Predefined message to request temperature data
byte TempCmd[] = { 0x01, 0x04, 0x00, 0x03, 0x00, 0x01, 0xC1, 0xCA };
RS485Serial.write(TempCmd, sizeof(TempCmd));
delay(10); // Small delay to ensure message is sent
}
void receiveRS485Message() {
byte buffer[32]; // Buffer to hold incoming data
int index = 0;
// Read incoming bytes
while (RS485Serial.available() && index < sizeof(buffer)) {
buffer[index++] = RS485Serial.read();
// Process the received data
for (int i = 0; i < index; i++) {
if (i == 3) {
PH_R[0] = String(buffer[i], HEX);
value[0] = (uint8_t)strtol(PH_R[0].c_str(), NULL, 16);
} else if (i == 4) {
PH_R[1] = String(buffer[i], HEX);
value[1] = (uint8_t)strtol(PH_R[1].c_str(), NULL, 16);
} else if (i == 5) {
PH_R[2] = String(buffer[i], HEX);
value[2] = (uint8_t)strtol(PH_R[2].c_str(), NULL, 16);
} else if (i == 6) {
PH_R[3] = String(buffer[i], HEX);
value[3] = (uint8_t)strtol(PH_R[3].c_str(), NULL, 16);
} else if (i == 12) {
Temp[0] = String(buffer[i], HEX);
} else if (i == 13) {
Temp[1] = String(buffer[i], HEX);
}
}
Serial.println();
// Combine temperature bytes into a string and convert to integer
result = combineNumbersToString(Temp, sizeof(Temp) / sizeof(Temp[0]));
long intValue = strtol(result.c_str(), NULL, 16);
Serial.println(intValue / 10); // Print temperature value
// Rearrange bytes for pH value and create float
uint8_t reorderedBytes[4] = { value[1], value[0], value[3], value[2] };
float PH_R;
memcpy(&PH_R, reorderedBytes, sizeof(PH_R));
Serial.println(PH_R, 3); // Print pH value with 3 decimal places
delay(500);
// Update Blynk values based on pin state
int pinState = mcp.digitalRead(8);
if (pinState == LOW) {
Blynk.virtualWrite(V1, PH_R);
Blynk.virtualWrite(V2, intValue / 10);
Blynk.virtualWrite(V3, 1);
} else {
Blynk.virtualWrite(V1, 0);
Blynk.virtualWrite(V2, 0);
Blynk.virtualWrite(V3, 0);
}
}
}
String combineNumbersToString(String numbers[], int size) {
String combined = "";
// Concatenate each number
for (int i = 0; i < size; i++) {
combined += numbers[i];
}
return combined;
}
void scheduleDeepSleep() {
struct tm timeinfo;
if (getLocalTime(&timeinfo)) {
if (timeinfo.tm_hour == 0 && timeinfo.tm_min == 0) {
ESP.restart();
} else if (timeinfo.tm_hour == 0 && timeinfo.tm_min == 5) {
esp_sleep_enable_timer_wakeup(60 * 1000000); // 1 minute deep sleep
esp_deep_sleep_start();
}
}
}