I recreate this project "Arduino, Monitoring Door-Opening via Gmail", but instead of hard-coded email address, I make an web user interface to let user add/delete multiple email address via web.



Things we needs
× 1
PHPoC WiFi Shield 2 for Arduino
It also works with one of the following shields:
- PHPoC WiFi Shield for Arduino
- PHPoC Shield for Arduino
- PHPoC WiFi Shield 2 for Arduino
- PHPoC Shield 2 for Arduino
× 1
Working Flow


Adding/Deleting Email from Email List

User ----(email)----> Web ----------> Arduino --------> EEPROM

Sending Email Notification (when an event occurs)
  • Reading email list from EEPROM
  • Sending notifications to each email address one by one.


User Interface


How To

Similar to this project https://www.hackster.io/phpoc_man/ar...via-web-ea5902


Source Code

Arduino code
Code:
#include "SPI.h"
#include "Phpoc.h"
#include <EEPROM.h>

#ifndef EOF
#define EOF (-1)
#endif

#define CMD_ARDUINO_DEL 0
#define CMD_ARDUINO_GET 1
#define CMD_ARDUINO_ADD 2
#define CMD_WEB_CLR        5
#define CMD_WEB_UPD        6

#define MAX_NUM_EMAIL    10

class EepromCSV
{
    public:
        void clear(void);
        int line(void);
        String readLine(int line);
        void writeLine(String lineStr);
};

EepromCSV EepromCSV;
PhpocServer webServer(80);

String emailArray[MAX_NUM_EMAIL];
int numEmail;

int lastState = 1;
unsigned long lastUpdateTime;

void setup() {
    Serial.begin(9600);
    while(!Serial)
        ;
    Phpoc.begin(PF_LOG_SPI | PF_LOG_NET);
    webServer.beginWebSocket("arduino");

    Serial.print("WebSocket server address : ");
    Serial.println(Phpoc.localIP());

    //EepromCSV.clear();
    eepromToEmailList(); // load email from EEPROM

    lastState = digitalRead(A0);
    lastUpdateTime = millis();
}

void loop() {
    checkEmailListUpdate(); // check whether there is any config command from Web or not.

    int currentState = digitalRead(A0);

    if((millis() - lastUpdateTime) > 1000) // 1 second
    {
        if(lastState != currentState)
        {
            if (lastState == 1 && currentState == 0)
            { // if door is opened...
                for(int i = 0; i < numEmail; i++)
                {
                    sendRelayGmail(emailArray[i]);
                    delay(1000);
                }

                lastUpdateTime = millis();
            }
            else
            if(lastState == 0 && currentState == 1)
            { // if door is closed...
                // Write codes in the same way
            }

            lastState = currentState;
        }
    }
}

void sendRelayGmail(String emailAddress)
{
    PhpocEmail email;
    char charEmailAddr[50];

    emailAddress.toCharArray(charEmailAddr, emailAddress.length() + 1);

    email.setOutgoingServer("smtp.gmail.com", 587);
    email.setOutgoingLogin("example@gmail.com", "example_password");

    email.setFrom("example@gmail.com", "From Arduino Gmail");
    email.setTo(charEmailAddr, "To Whom It May Concern");

    email.setSubject(F("Door is opened. [#905]"));  // Mail Subject

    // Mail Contents
    email.beginMessage();
    email.println(F("#905"));
    email.println("");
    email.println(F("Door is opened."));
    email.endMessage();

    if (email.send() > 0)  // Send Email
        Serial.print(F("Your Mail has been sent successfully to "));
    else
        Serial.print(F("Your Mail is not sent to "));

    Serial.println(emailAddress);
}
void eepromToEmailList(void) {
    int lineCount = EepromCSV.line();

    if(lineCount > MAX_NUM_EMAIL)
        lineCount = MAX_NUM_EMAIL;

    for(int i = 0; i < lineCount; i++)
    {
        String line;

        line = EepromCSV.readLine(i);
        emailArray[i] = line.substring(0, line.indexOf("\n"));
    }

    numEmail = lineCount;
}
void sendToWeb(String data) {
    char wbuf[50];

    data.toCharArray(wbuf, data.length() + 1);
    webServer.write(wbuf, data.length());
}
void checkEmailListUpdate(void) {
    // wait for a new client:
    PhpocClient client = webServer.available();

    if (client)
    {
        // read a string that is terminated by a carriage return and a newline
        // characters:
        String data = client.readLine();

        if(data)
        {
            String email;
            int cmd;

            cmd = data.substring(0, 1).toInt();

            if(cmd == CMD_ARDUINO_GET)
            {
                int lineCount = EepromCSV.line();

                sendToWeb(String(CMD_WEB_CLR) + ",0\n"); /* tell web clear to load new email */

                for(int i = 0; i < lineCount; i++)
                {
                    email = EepromCSV.readLine(i); /* read email from EEPROM one by one */
                    sendToWeb(String(CMD_WEB_UPD) + "," + email + "\n"); /* send email to Web */
                }
            }
            else
            if(cmd == CMD_ARDUINO_DEL)
            {
                email = data.substring(2, data.indexOf("\r\n"));

                EepromCSV.clear(); /* clear to update new email */

                for(int i = 0; i < numEmail; i++)
                {
                    if(!emailArray[i].equals(email))
                        EepromCSV.writeLine( emailArray[i]); /* write email to EEPROM */
                }

                eepromToEmailList(); /* reload email from EEPROM */
            }
            else
            if(cmd == CMD_ARDUINO_ADD)
            {
                email = data.substring(2, data.lastIndexOf("\r\n"));

                if(email.length())
                {
                    EepromCSV.writeLine(email); /* write email to EEPROM */
                    eepromToEmailList(); /* reload email from EEPROM */
                }
            }
        }
    }
}

void EepromCSV::clear(void) {
    EEPROM.write(0, EOF);
    Serial.println(F("EepromCSV::clear"));
}
int EepromCSV::line(void) {
    int lineCount   = 0;
    int address     = 0;
    char value;

    while(1) {
        value = EEPROM.read(address++);

        if(value == '\n')
            lineCount++;
        else if(value == EOF)
            return lineCount;
    }
}
String EepromCSV::readLine(int line) {
    String retStr   = "";
    char value;
    int lineIndx    = 0;
    int address     = 0;

    while(lineIndx < line) {
        value = EEPROM.read(address++);
        if(value == '\n')
            lineIndx++;
        else if (value == EOF) {
            return "";
        }
    }

    while(1) {
        value = EEPROM.read(address++);

        if(value == '\n' || value == EOF)
        {
            Serial.print(F("EepromCSV::readLine:"));
            Serial.println(retStr);

            return retStr;
        }
        else
            retStr += value;
    }
}
void EepromCSV::writeLine(String lineStr) { /* add new line at the end of CSV file*/
    int address, length;

    address    = 0;
    length    = lineStr.length();

    while((char)EEPROM.read(address++) != EOF)
        ;
    address--;

    for(int i = 0; i < length; i++)
        EEPROM.write(address++, lineStr.charAt(i));

    EEPROM.write(address++, '\n');
    EEPROM.write(address, EOF);

    Serial.print(F("EepromCSV::writeLine:"));
    Serial.println(lineStr);
}


Web User Interface code
PHP Code:
<!DOCTYPE html>
<html>
<head>
<title>Arduino - Configure via Web</title>
<meta name="viewport" content="width=device-width, initial-scale=0.7, maximum-scale=0.7">
<meta charset="utf-8">
<style>
body { text-align: center; font-size: 100%; font-family: Roboto;}
#header { background-color: #00979d; color: white; padding: 5px; margin-bottom: 15px}
h2 { font-weight: bold; font-size: 120%; }
table th { font-weight: bold; font-size: 120%; border-bottom: 8px solid #00979d; }
table td { font-weight: bold; font-size: 120%; height: 40px; }
select, input { font-size: 100%; font-family: Roboto;}
.button { border-top: 10px solid white; font-size:130%; background-color: red; color:white;}

</style>
<script>
var CMD_ARDUINO_DEL    = 0;
var CMD_ARDUINO_GET    = 1;
var CMD_ARDUINO_ADD    = 2;
var CMD_WEB_CLR        = 5;
var CMD_WEB_UPD        = 6;
var dayLookupTable = ["", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
var email_list = new Array();
var ws = null;
var buffer = "";

function init() {
    if(ws == null) {
        var ws_host_addr = "<?echo _SERVER("HTTP_HOST")?>";
        if((navigator.platform.indexOf("Win") != -1) && (ws_host_addr.charAt(0) == "[")) {
            // network resource identifier to UNC path name conversion
            ws_host_addr = ws_host_addr.replace(/[\[\]]/g, '');
            ws_host_addr = ws_host_addr.replace(/:/g, "-");
            ws_host_addr += ".ipv6-literal.net";
        }

        ws = new WebSocket("ws://" + ws_host_addr + "/arduino", "text.phpoc");
        ws.onopen = ws_onopen;
        ws.onclose = ws_onclose;
        ws.onmessage = ws_onmessage;
    }
    else
        ws.close();
}
function ws_onopen() {
    setTimeout(function() {
        ws.send(CMD_ARDUINO_GET + ",0\r\n");
    }, 100);
}
function ws_onclose() {
    ws.onopen = null;
    ws.onclose = null;
    ws.onmessage = null;
    ws = null;

    alert("Not connected to Arduino!");
}
function ws_onmessage(e_msg) {
    e_msg = e_msg || window.event; // MessageEvent

    buffer += e_msg.data;
    buffer = buffer.replace(/\r\n/g, "\n");
    buffer = buffer.replace(/\r/g, "\n");

    console.log(buffer);
    while(buffer.indexOf("\n") == 0)
        buffer = buffer.substr(1);

    while(buffer.indexOf("\n") >= 0) { // because multiple update data may come at the same time
        var data = buffer.substr(0, buffer.indexOf("\n"));
        buffer = buffer.substr(buffer.indexOf("\n") + 1);

        var arr = data.split(",");
        var cmd = parseInt(arr[0]);

        if(cmd == CMD_WEB_CLR) {
            email_list = new Array();

            var emailTable = document.getElementById("emailTable");
            while( emailTable.rows.length > 2)
                emailTable.deleteRow(1);
        }
        else if(cmd == CMD_WEB_UPD) {
            var email = arr[1];

            email_list.push(email);

            var emailTable = document.getElementById("emailTable");
            var numRow = emailTable.rows.length;
            var newRow = emailTable.insertRow(numRow - 1);
            newRow.insertCell().innerHTML = email;
            newRow.insertCell().innerHTML = '<span style="color:red;" onclick="deleteEmail(this)">delete</span>';

            newRow.cells[0].style.paddingRight="50px"
            newRow.cells[0].style.textAlign = "right";
            newRow.style.color = "#1E90FF";
        }
    }
}
function deleteEmail(event) {
    var rowIndex = event.parentElement.parentElement.rowIndex;
    document.getElementById("emailTable").deleteRow(rowIndex);

    var email = email_list[rowIndex - 1];
    email_list.splice(rowIndex - 1, 1);

    if(ws == null)
        alert("Not connected to Arduino!");
    else
        ws.send(CMD_ARDUINO_DEL + "," + email + "\r\n");
}
function addEmail(event) {
    var emailTable = document.getElementById("emailTable");
    var rowIndex = event.parentElement.parentElement.rowIndex;
    var row  = emailTable.rows[rowIndex];
    var email = row.cells[0].childNodes[0].value;

    if(!email)
        return;

    row.cells[0].innerHTML = email;
    row.cells[1].innerHTML = '<span style="font-size:120%; color:red;" onclick="deleteEmail(this)">delete</span>';

    row.cells[0].style.paddingRight="50px"
    row.cells[0].style.textAlign = "right";
    row.style.color = "#1E90FF";

    email_list.push(email);

    if(ws == null)
        alert("Not connected to Arduino!");
    else
        ws.send(CMD_ARDUINO_ADD + "," + email + "\r\n");
}
function newEmail() {
    var emailTable = document.getElementById("emailTable");
    var numRow = emailTable.rows.length;
    var newRow = emailTable.insertRow(numRow - 1);
    var cell0 = newRow.insertCell();
    var cell1 = newRow.insertCell();

    cell0.innerHTML = '<input type="email" name="email" style="border-color: red; width:80%">';
    cell1.innerHTML = '<span style="color:red;" onclick="addEmail(this)">add</span>';
}

window.onload = init;
</script>
</head>
<body>
<div id="header">
<span style="font-size:150%; font-weight: bold;">ARDUINO - EMAIL LIST</span><br>
<span style="font-size:130%; font-weight: normal;">Web To EEPROM</span>
</div>
<table id="emailTable"  style="width:100%; table-layout:fixed;">
    <tr>
        <th>EMAIL ADDRESS</th>
        <th width="30%">ADD / DELETE</th>
    </tr>
    <tr>
        <td class="button" colspan="2" onclick="newEmail(this)">NEW</td>
    </tr>
</table>
<br>
<h2>
</h2>
</body>
</html>