/** Battery Charger / Alarm LED Monitor. Send Notification to Mobile phone. WeMos D1 Mini. (c) July 2023 vwlowen.co,uk **
LEDs:
WiFi Connected (RED) Flashing: Connected. Waiting for start button.
Steady: Connected. Device monitoring normally.
Sensor (GREEN) Off: LED on 'host device (eg Charger) is off.
On: LED on host device is on.
Notification (Yellow) Off: Idle. Waiting for change of Sensor status.
On: Sensor status changed.. Notification request successfully sent to PushSafer.
Flashing: As 'On' but only a few notifications are still available from PushSafer before top_up.
Test Mode(Blue) Flashing: Device is in TEST mode. Opertes normally but doesn't send notification request.
JUMPERS:
Test Jumper Closed for test mode.
Falling Jumper Closed: Device sends notification request when Sensor LED goes OFF (falling).
Open: Device sends notification request when Sensor LED goes ON (rising). **/
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <Arduino_JSON.h> // https://github.com/arduino-libraries/Arduino_JSON
#define NOTIFICATION_SENT_LED D1 // Define I/O pins for LEDs.
#define CHARGING_LED D2
#define CONNECTED_LED D3
#define TEST_MODE_LED D4 // Built-in LED is connected to output pin D4.
#define START_BUTTON D5 // Define I/O pins for the Start button, TEST jumper and FALLING jumper.
#define TEST_JUMPER D6
#define NOTIFY_ON_FALL D7 // Jumper/Switch closed (LOW) sends notification when Charging LED goes out.
// Jumper/Switch open (HIGH) sends notification when Charging LED comes on.
#define WIFI_TIMEOUT 10000 // Define WiFi connection attempt timeout (10 seconds)
#define SENSOR_TIMER 2000 // Read photo-diode sensor every 2 seconds.
#define THRESHOLD 25 // Charging LED on/off threshold. (Depends on charger's LED
// brightness and photo-diode's sensitivity).
#define ATTEMPTS 3 // Maximum number of tries to contact PushSafer.
#define NOTIFICATIONS_LOW 10 // Flash Notification Sent LED when numnber of available
// notifications falls below this figure. (Time to top up!)
/*** Change the following two lines to your own router's WiFi SSID and Password ******/
const char* ssid = "*******"; // Your WiFi SSID.
const char* password = "**********"; // Your WiFi Password.
String wifi_hostname = "charger-alert"; // Hostname *might* show in router's 'connected' list
String pushSaferURL = "http://www.pushsafer.com/api"; // PushSafer server URL.
String pushSaferKey = "********************"; // PushSaferKey and DeviceID are obtained from
String deviceID = "12345"; // your PushSafer Account.
String title = "ESP8266 Charger Monitor";
String message = "Charge complete.";
String icon = "175"; // Car Icon for notification on phone.
String pushSaferPath;
const int adc = A0; // D1 Mini's only analogue port.
int adc_value = 0;
bool charging = false; // Initialise flags and attempts counter.
bool notification_Sent_Flag = false;
bool test_flag = false;
bool falling = true;
int notifyAttempts = 0;
bool few_left = false;
int few_left_state = LOW;
unsigned long few_left_timer = 0; // Timer to flash Notification_Sent LED when only a few notifications available.
unsigned long wifi_timer = 0; // Timer to flash WiFi LED.
unsigned long test_timer = 0; // Timer to blink built-in LED when in Test Mode.
unsigned long read_timer = 0; // Timer to read photo-diode.
int readSensor() {
int adc_avg = 0;
int raw = 0;
for (int i = 0; i< 50; i++) {
raw = raw + analogRead(adc);
delay(10);
}
adc_avg = raw / 50;
if (test_flag) {
Serial.print("ADC value: "); // Print the value from the sensor for debugging.
Serial.println(adc_avg);
}
return adc_avg;
}
void blinkTestLED() { // Blink built-in LED if in Test Mode.
if (millis() - test_timer >= 1000) {
test_timer = millis();
digitalWrite(TEST_MODE_LED, LOW);
delay(10);
digitalWrite(TEST_MODE_LED, HIGH);
}
}
void setup() {
Serial.begin(115200); // Serial port useful for debugging response messages
// from PushSafer server.
pinMode(CHARGING_LED, OUTPUT);
pinMode(CONNECTED_LED, OUTPUT);
pinMode(NOTIFICATION_SENT_LED, OUTPUT);
pinMode(TEST_MODE_LED, OUTPUT);
pinMode(START_BUTTON, INPUT_PULLUP);
pinMode(TEST_JUMPER, INPUT_PULLUP);
pinMode(NOTIFY_ON_FALL, INPUT_PULLUP);
title.replace(" ", "%20"); // Replace spaces with %20 for use in PushSafer URL
message.replace(" ", "%20");
pushSaferPath = pushSaferURL + // String to send to PushSafer server.
"?d=" + deviceID +
"&i=" + icon +
"&t=" + title +
"&m=" + message +
"&k=" + pushSaferKey;
Serial.println(" ");
Serial.println(pushSaferPath); // Check PushSafer URL on Serial Monitor for debugging.
WiFi.hostname(wifi_hostname.c_str());
WiFi.begin(ssid, password); // Start WiFi
unsigned long startAttemptTime = millis();
while (WiFi.status() != WL_CONNECTED && // Attempt to connect to your home router.
millis() - startAttemptTime < WIFI_TIMEOUT){
delay(10);
}
test_flag = digitalRead(TEST_JUMPER) == LOW; // Set Test Flag if jumper is closed.
falling = digitalRead(NOTIFY_ON_FALL) == LOW; // Low (falling) means looking for charging LED to go out.
digitalWrite(TEST_MODE_LED, HIGH);
if (test_flag) {
Serial.println("Waiting for Start Button");
}
while (digitalRead(START_BUTTON) == HIGH) { // Wait in a loop until the sensor is set up on the charger
ESP.wdtFeed(); // Keep the ESP8266 watchdog happy.
adc_value = readSensor();
digitalWrite(CHARGING_LED, (adc_value >= THRESHOLD)); // Show sensor value High or Low (Echo Charger's LED)
if (WiFi.status() == WL_CONNECTED) {
if (millis() - wifi_timer >= 200) { // Flash Connected LED status to indicate the device..
wifi_timer = millis(); // is waiting for the Start button to be pressed.
digitalWrite(CONNECTED_LED, !digitalRead(CONNECTED_LED)); // If it doesn't flash, WiFi isn't connected.
}
} else {
digitalWrite(CONNECTED_LED, LOW);
}
if (test_flag) { // Blink Built-in LED if device is in test mode.
blinkTestLED();
}
}
}
void loop() {
digitalWrite(CONNECTED_LED, (WiFi.status() == WL_CONNECTED)); // Show WiFi Connected status.
if (millis() - read_timer > SENSOR_TIMER) { // Read sensor every 2 seconds.
adc_value = readSensor(); // Get ADC value from photo-diode.
read_timer = millis(); // Reset delay timer.
digitalWrite(CHARGING_LED, (adc_value >= THRESHOLD)); // Show value (high or low) on LED (Echo LED on charger)
}
if(WiFi.status()== WL_CONNECTED) {
if (falling) { // Looking for Charging LED to go out
if (adc_value >= THRESHOLD) charging = true; // Set 'charging' flag when charging LED on Charger lights.
// If charging light on charger goes out....
if (charging && (notifyAttempts < ATTEMPTS) && (adc_value < THRESHOLD) && (notification_Sent_Flag == false)) {
charging = false;
if (!test_flag) sendNotification(); // If the test jumper is open, send message to PushSafer.
digitalWrite(NOTIFICATION_SENT_LED, (notification_Sent_Flag || test_flag));
notifyAttempts++; // Make only 3 attempts to contact PushSafer.
}
}
else if (!falling) { // Looking for charging LED to light
if (adc_value <= THRESHOLD) charging = true; // Set 'charging' flag when charging LED on Charger goes out.
// If cahrging light comes on....
if (charging && (notifyAttempts < ATTEMPTS) && (adc_value > THRESHOLD) && (notification_Sent_Flag == false)) {
charging = false;
if (!test_flag) sendNotification(); // If the test jumper is open, send message to PushSafer.
digitalWrite(NOTIFICATION_SENT_LED, (notification_Sent_Flag || test_flag));
notifyAttempts++; // Make only 3 attempts to contact PushSafer.
}
}
}
if (test_flag) { // Blink Built-in LED if device is in test mode.
blinkTestLED();
}
if (few_left) { // Flash Notification Sent LED if only a few Notifications left.
if (millis() - few_left_timer >= 250) {
few_left_timer = millis();
few_left_state ? few_left_state = LOW : few_left_state = notification_Sent_Flag;
digitalWrite(NOTIFICATION_SENT_LED, few_left_state);
}
}
}
void sendNotification() { // Send message to PushSafer to push notification to your phone.
WiFiClient client;
HTTPClient http;
Serial.println("Making HTTP request to ...");
Serial.println(pushSaferPath);
http.begin(client, pushSaferPath.c_str());
int httpCode = http.GET(); // Send the request
if (httpCode > 0) { // Check the returning HTTP code
String payload = http.getString(); // Get the response back from the server
Serial.println("HTTP Response: "); // Print the response on Serial Monitor (for debugging)
Serial.println(payload);
JSONVar doc = JSON.parse(payload); // Parse the JSON data into JSONVar 'doc'
int result = doc["status"]; // Get 'status' from JSON doc. (1 = success)
notification_Sent_Flag = (result == 1); // Set notification_Sent flag if valid response from PushSafer
if (notification_Sent_Flag) { // Look for number of remaining notifications available
int numLeft = doc["available"];
few_left = (numLeft <= NOTIFICATIONS_LOW); // Set "few_left" flag if available number is less than preset.
Serial.print("Available: ");
Serial.println(numLeft);
}
} else {
notification_Sent_Flag = false; // No response received from PushSafer.
charging = true; // reset 'Charging' flag to enable another attempt (max 3 attempts)
}
http.end(); // Close the HTTP connection
delay(5000);
}