John R McAlpine V Mac
Published © CC BY-NC

You've-Got-Mail

Notifications aren't just for email any more. Get real time alerts directly to your devices from a solar power Particle Photon via IFTTT.

IntermediateFull instructions provided6 hours3,133
You've-Got-Mail

Things used in this project

Hardware components

Photon
Particle Photon
×1
TP4056 LIPO charge board
×1

Software apps and online services

Maker service
IFTTT Maker service
ThingSpeak API
ThingSpeak API

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)

Story

Read more

Schematics

asciicad

Code

macsboost youve-got-mail particle code

Arduino
load on the particle IDE
/*This sketch experiments with low power for battery/solar operation and thingspeak.
 a magnetic reed switch is connected to D0.  The particle sleeps and wakes on a falling edge interrupt at D0.
 if triggered it publishes a notification that can be detected by IFTTT and sends a notification
 to your device.
 on every interrupt and on wakeup a update is published to thingspeak with voltage, current, RSSI and # of triggers.
                                       +-----+
 *                          +----------| USB |----------+
 *                          |          +-----+       *  |
 *       /------------------| [ ] VIN           3V3 [ ] |---------
 *      |                   | [ ] GND           RST [ ] |         \
 *    10K                   | [ ] TX           VBAT [ ] |          |
 *      |                   | [ ] RX  [S]   [R] GND [*] |-------   |
 *      |                   | [ ] WKP            D7 [ ] |       \  |
 *       \                  | [ ] DAC +-------+  D6 [ ] |       |  |  
 *       /------batt sense->| [*] A5  |   *   |  D5 [ ] |       |  |
 *    10K - batt sense gnd->| [*] A4  |Photon |  D4 [ ] |     10K  |
 *  TP4056 Pin 2 curr sense | [*] A3  |       |  D3 [ ] |       |  |
 *                          | [ ] A2  +-------+  D2 [ ] |       |  |
 *                          | [ ] A1             D1 [ ] |       |  /
 *                          | [ ] A0             D0 [*] |<-magnetic reed (door) switch
 *                          |                           |
 *                           \    []         [______]  /
 *                            \_______________________/
 *
 *
 */

/*  begin particle webhook code snippit to add to particle webhook interface on console
{
    "event": "thingSpeakWrite_",
    "url": "https://api.thingspeak.com/update",
    "requestType": "POST",
    "form": {
        "api_key": "{{k}}",
        "field1": "{{1}}",
        "field2": "{{2}}",
        "field3": "{{3}}",
        "field4": "{{4}}",
        "field5": "{{5}}",
        "field6": "{{6}}",
        "field7": "{{7}}",
        "field8": "{{8}}",
        "lat": "{{a}}",
        "long": "{{o}}",
        "elevation": "{{e}}",
        "status": "{{s}}"
    },
    "mydevices": true,
    "noDefaults": true
}
*/

ApplicationWatchdog wd(120000, System.reset);

char publishString[40];
int mailpin = D0;
int volttestpin = A5;
int voltpowerpin = A4;
int currentsensepin = A3;
float chargecurrent = 0;
float batteryvolts = 0;
const int sleepytime = 1800; //seconds to sleep 3600=1hr
const int longsleepytime = 3600; //seconds to sleep 3600=1hr

const String key = "THINGSPEAK_KEY";


int rssival = 0;
volatile bool mailsend = FALSE;
volatile bool rssisend = FALSE;
int mailtriggers = 0;
long waketime = 0;
SYSTEM_THREAD(ENABLED); //enable multitasking.  allows the ability to catch the mailpin trigger and send the message
SYSTEM_MODE(AUTOMATIC);  //run code. then connect     
     
void rssi_update()
{
    //delay (2000);
    static int count = 0;
    Serial.println(count++);
    rssival = WiFi.RSSI();  //measure RSSI
    chargecurrent = analogRead(currentsensepin)*3.3/4096;   //measure solar charge current (A)
    batteryvolts = checkbattery();  //measure battery voltage
    sprintf(publishString,"%d",rssival);
    bool success = Particle.publish("RSSI",publishString);
    
    sprintf(publishString, "%1.4f", batteryvolts);

       Particle.publish("thingSpeakWrite_All", +
     "{ \"1\": \"" + String(rssival) + "\"," +
       "\"2\": \"" + String(batteryvolts) + "\"," +
       "\"3\": \"" + String(mailtriggers) + "\"," +
       "\"5\": \"" + String(chargecurrent) + "\"," +  //channel 5 due to a legacy SOC channel being calculated on thingspeak via a react.
     //"\"5\": \"" + String(var4) + "\"," +
       "\"k\": \"" + key + "\" }", 60, PRIVATE);
       

    if (success == TRUE) {
        //delay(10000);
        rssisend = FALSE; //if sent, then turn of the send flag, otherwise let it try again.
    }
}


void enablemailsend(void){
    mailsend=TRUE;
    digitalWrite(D7,1);
}

void setup() {
    //setADCSampleTime(ADC_SampleTime_239Cycles5);  //sets adc to longest time for low noise
    Time.zone(-4);  //set eastern time zone
    pinMode(mailpin,INPUT);
    pinMode(voltpowerpin, INPUT);
    pinMode(currentsensepin, INPUT);
    pinMode(D7, OUTPUT);
    attachInterrupt(mailpin, enablemailsend, FALLING);
    Particle.variable("mailtrig", mailtriggers);
    rssisend = TRUE;
}


void loop() {
     //wd.checkin();  //watchdog checkin
     //do not checkin the watchdog.  the counter seems to reset each time the system boots.  The watchdog
     //should therefore only cause a reset if the system is stuck, on and cant connect to wifi.
     
     
    if ((Particle.connected())&&(mailsend == TRUE)&&WiFi.ready()) 
    {
        mailnotification();
    }
    
    if ((Particle.connected())&&(rssisend == TRUE)&&WiFi.ready()) 
    {
        rssi_update();
    }
    

    if ((millis()-waketime > 30000) && (mailsend == FALSE) && (rssisend == FALSE)) //if everything sent ok under 30 seconds, then sleep for short time
    {
        Particle.disconnect();
        
        //System.sleep(mailpin,RISING,30); 
        delay(100);
        System.sleep(mailpin,FALLING,sleepytime);
        pinMode(mailpin,INPUT); // this may need resetting after sleep.
        waketime = millis();  //millis haults when sleeping.  find out the time on boot and compare from there.
        rssisend = TRUE;  //on wakeup report rssi but do not report mail trigger
        mailsend = FALSE;
        delay(20); //wait to check if mail rx.. could be some debouncing
        if (digitalRead(mailpin) == LOW) {  //this test triggers a mail send if woken up by the mailpen being drawn low
            enablemailsend();
        } 
    } 
    
    if ((millis()-waketime > 60000)) //if photon awake for over 60 seconds then go back to sleep for long time. (unable to send, maybe lost wifi)
        {
            Particle.disconnect();
        
            //System.sleep(mailpin,RISING,30); 
            delay(100);
            System.sleep(mailpin,FALLING,longsleepytime);
            pinMode(mailpin,INPUT); // this may need resetting after sleep.
            waketime = millis();  //millis haults when sleeping.  find out the time on boot and compare from there.
            rssisend = TRUE;  //on wakeup report rssi but do not report mail trigger
            mailsend = FALSE;
            delay(20); //wait to check if mail rx.. could be some debouncing 
            if (digitalRead(mailpin) == LOW) {  //this test triggers a mail send if woken up by the mailpen being drawn low
                enablemailsend();
            } 
        }


    
    if (Particle.connected() == false) 
    {
        Particle.connect();
    }
    /*if (waitFor(Particle.connected, 20000))
    {
    }
    */
}

float checkbattery(){
    float battvolts;
    pinMode(volttestpin, INPUT);  
    pinMode(voltpowerpin, OUTPUT); //sent power pin as output
    digitalWrite(voltpowerpin, 0); //send a 0, or LOW to turn on voltage test
    delay(1); //wait for volts to settle good measure
    battvolts = analogRead(volttestpin); //sample voltage
    battvolts = float(battvolts)*3.3/4096.0*2.0*3.85/3.827*4.06/4.08;  //calibrate voltage reading
    pinMode(voltpowerpin, INPUT); //disable powerpin and set as high Z input
    return(battvolts); //return calibrated battery voltage
}

void mailnotification(void){
    digitalWrite(D7,1);
    rssi_update();
    sprintf(publishString, "%1.4f", checkbattery());
    Particle.publish("mail/volts", publishString,60,PRIVATE);
    
    //sprintf(publishString, "%d", mailtriggers);
    bool success = Particle.publish("youve-got-mail", Time.format(Time.now(), "%I:%M%p"), 60, PUBLIC);
    delay(1000);
    if (success == TRUE) {
        mailtriggers++;
        mailsend = FALSE; //if sent, then turn off the send flag, otherwise let it try again.
        digitalWrite(D7,0);
        }
}

thingspeak schema

PHP
{
    "event": "thingSpeakWrite_",
    "url": "https://api.thingspeak.com/update",
    "requestType": "POST",
    "form": {
        "api_key": "{{k}}",
        "field1": "{{1}}",
        "field2": "{{2}}",
        "field3": "{{3}}",
        "field4": "{{4}}",
        "field5": "{{5}}",
        "field6": "{{6}}",
        "field7": "{{7}}",
        "field8": "{{8}}",
        "lat": "{{a}}",
        "long": "{{o}}",
        "elevation": "{{e}}",
        "status": "{{s}}"
    },
    "mydevices": true,
    "noDefaults": true
}

thingspeak app code

MATLAB
calculates battery state of charge from battery voltage
% Reads voltage and converts to an approximate state of charge level
% writes this level back to the channel


% Channel ID to read data from
readChannelID = [ENTER YOUR CHANNEL ID HERE];
% Temperature Field ID
VoltsFieldID = 2;

% Channel Read API Key 
% If your channel is private, then enter the read API
% Key between the '' below: 
readAPIKey = 'ENTER YOUR READ KEY HERE';

% To store the battery state of charge, based on battery voltage
% than the one used for reading data. To write to a channel, assign the
% write channel ID to the 'writeChannelID' variable, and the write API Key
% to the 'writeAPIKey' variable below. Find the write API Key in the right
% side pane of this page.

% TODO - Replace the [] with channel ID to write data to:
writeChannelID = [ENTER YOUR CHANNEL ID HERE];
% TODO - Enter the Write API Key between the '' below:
writeAPIKey = 'ENTER YOUR WRITE KEY HERE';

% Read latest temperature data from the MathWorks Weather Station Channel.
% Learn more about the THINGSPEAKREAD function by going to the Documentation tab on
% the right side pane of this page.

volts = thingSpeakRead(readChannelID, 'Fields', VoltsFieldID, 'ReadKey', readAPIKey);

% Convert to battery percentage
%volts = str2double(volts);
battvolts = volts;

%soclookupvolts   = [3.0  3.55 3.60  3.69  3.75  3.80 3.95  4.15];  
%soclookuppercent = [0    5    10    20    50    60   80    100 ];
%soclevel = 0;
%soclevel == tablelookup(soclookupvolts, soclookuppercent, battlevel);

x = battvolts;
y = -287.33*x^3 + 3484.7*x^2 - 13880*x + 18212;
soclevel = y;

display(battvolts, 'Volts');
display(soclevel, 'Percent');

% Write the temperature in Fahrenheit to another channel specified by the
% 'writeChannelID' variable

display(['Note: To successfully write data to another channel, ',...
    'assign the write channel ID and API Key to ''writeChannelID'' and ',...
    '''writeAPIKey'' variables above. Also uncomment the line of code ',...
    'containing ''thingSpeakWrite'' (remove ''%'' sign at the beginning of the line.)'])

% Learn more about the THINGSPEAKWRITE function by going to the Documentation tab on
% the right side pane of this page.

thingSpeakWrite(writeChannelID, 'Fields',[4],'Values',soclevel, 'Writekey', writeAPIKey);

Credits

John R McAlpine V Mac

John R McAlpine V Mac

12 projects • 49 followers
www.MACSBOOST.com Assistant Teaching Professor at UNC Charlotte MEGR3171 Instrumentation, Motorsports Research

Comments