#define BLYNK_TEMPLATE_ID "xxxxxxxxxx"
#define BLYNK_TEMPLATE_NAME "xxxxxxxxxx"

#define BLYNK_PRINT Serial
#include <Wire.h>
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <BlynkSimpleEsp8266.h>
#include <Adafruit_INA219.h>
#include <Adafruit_SSD1306.h>

char auth[] = "xxxxxxxxxx";
char ssid[] = "your wifi name";
char pass[] = "your wifi password";

#define I2C_ADDRESS 0x40
Adafruit_INA219 ina219(I2C_ADDRESS);

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

float shuntVoltage_mV = 0.0;
float Load_Voltage = 0.0;
float Source_Voltage = 0.0;
float Current = 0.0;
float Power = 0.0;
float Wh = 0;

unsigned long lastmillis = millis();
unsigned long previousMillis = 0;  // will store the last time the Wh was updated

void setup()
{
  Serial.begin(115200);
  
  // Initialize the OLED display and show a message
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // Address 0x3C for 128x32
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(10,10);
  display.print("Powered and");
  display.setCursor(10,20);
  display.print("trying to connect...");
  display.display();

  Blynk.begin(auth, ssid, pass);  // Start Blynk
  delay(1000); 
  while (!Serial); 
  Wire.begin();
  ina219.begin();
  display.clearDisplay();

  Serial.println("INA219 Current Sensor Example Sketch - Continuous");

  // Define the built-in LED pin and set it as output
  #define LED_BUILTIN 2
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop()
{
  Blynk.run(); // Initiates Blynk

  unsigned long currentMillis = millis();

  if (Blynk.connected()) { // If connected to Blynk
    // Your existing code to read from the sensor and display on the OLED
    shuntVoltage_mV = ina219.getShuntVoltage_mV();
    Source_Voltage = ina219.getBusVoltage_V();
    Current = ina219.getCurrent_mA() / 1000;
    Power = ina219.getPower_mW() / 1000;
    Load_Voltage  = Source_Voltage + (shuntVoltage_mV / 1000);

    // Interpret any voltage less than 1V and greater than 0 as 0V
    if (Source_Voltage < 1.0 && Source_Voltage > 0.0) {
      Source_Voltage = 0.0;
    }

    // Update Wh once every second
    if (currentMillis - previousMillis >= 1000) {
      previousMillis = currentMillis;
      Wh = Wh + Power / 3600.0;
    }

    // Send to Blynk
    Blynk.virtualWrite(V0, Source_Voltage);
    Blynk.virtualWrite(V1, Load_Voltage);
    Blynk.virtualWrite(V2, Current);
    Blynk.virtualWrite(V3, Power);
    Blynk.virtualWrite(V4, Wh);

    //Display on OLED
    display.clearDisplay();
    display.setCursor(10,10);
    display.print("V: ");
    display.print(Source_Voltage, 2);
    display.setCursor(74,10);
    display.print("A: ");
    display.print(Current, 2);
    display.setCursor(10,20);
    display.print("W: ");
    display.print(Power, 2);
    display.setCursor(74,20);
    display.print("Wh: ");
    display.print(Wh, 2);
    display.display();
  } else { // If not connected to Blynk
    // Display a message on the OLED
    display.clearDisplay();
    display.setCursor(10,10);
    display.print("Failed to");
    display.setCursor(10,20);
    display.print("connect to Blynk");
    display.display();
  }

  // Call the blinkLED function
  blinkLED();
}

void blinkLED() {
  if (Blynk.connected()) { // If connected to Blynk
    digitalWrite(LED_BUILTIN, HIGH); // Turn on the LED
    delay(1000); // Wait a second
    digitalWrite(LED_BUILTIN, LOW); // Turn off the LED
    delay(1000); // Wait a second
  } else { // If not connected to Blynk
    digitalWrite(LED_BUILTIN, HIGH); // Turn on the LED
    delay(100); // Wait a tenth of a second
    digitalWrite(LED_BUILTIN, LOW); // Turn off the LED
    delay(100); // Wait a tenth of a second
  }
}
