Skip to content

Commit 15a1849

Browse files
committed
refactor code, update README
1 parent c8ab166 commit 15a1849

10 files changed

+113
-67
lines changed

.gitignore

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
1-
tests
2-
*.env
3-
*.json
1+
config/env
2+
data/response.json

README.md

+34-18
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,56 @@
11
# arduino-gmail-client
22

3-
A simple gmail client that makes cURL requests using gmail API to check for unread emails, the response is then used to control arduino pins. So if you connect an LED to the right pins, it will light up everytime you recieve an email!
3+
A simple gmail API client that makes cURL requests to check for unread emails, and controls arduino GPIO pins. So.. when you get an email, an LED lights up!
44

5-
This was something I wanted to try when I first stumbled upon gmail API and OAuth 2.0 protocol, finally got an arduino to implement it!!
5+
This is a proof of concept, something I wanted to try back when I came across gmail API and OAuth 2.0 for the first time, finally got an arduino to implement it!!
66

77
### How Does It Work?
88

9-
The code is extremely simple if you understand OAuth 2.0, if you don't, read [this article from google](https://developers.google.com/identity/protocols/oauth2). In a nutshell, to access information from a user (a.k.a the resource owner), a client must do the following:
10-
1. Get the authorization grant from the resource owner (for example, via a [consent screen](https://developers.google.com/identity/protocols/oauth2/web-server#userconsentprompt)).
11-
2. In exchange to the grant, you recieve an authorization code.
12-
3. Exchange the authorization code for access and refresh tokens from the authorization server.
13-
4. Use the access tokens to make API calls on behalf of the user.
14-
5. If the access token expires, use the refresh token to request another access token.
9+
Getting the unread email count using gmail API is not a simple task, since email is a private service a client cannot get access to information without permission.
1510

16-
Note: Refresh tokens are only provided on the first request. The IETF documentation on the OAuth 2.0 framework can be found [here](https://tools.ietf.org/html/rfc6749).
11+
OAuth 2.0 is a framework that lays out guidelines for this interaction, before requesting senstive information, getting consent from the user (a.k.a resource owner) is mandatory. Once obtained, the client can exchange it (consent) for temporary access tokens, which must be sent with every future API call that is requesting user data ([more info](https://developers.google.com/identity/protocols/oauth2)).
1712

18-
### What You'll Need To Run This Locally
13+
Signals are sent to the arduino board based on the response obtained from the API requests, GPIO pins are controlled using standard firmata protocol, python APIs for the same are provided by the pyFirmata library.
1914

20-
#### Setting Up the API Client
15+
### How Do I Run This?
2116

22-
You'll need to just follow [this tutorial](https://developers.google.com/identity/protocols/oauth2/web-server#top_of_page) and get the following fields:
17+
#### Set Up an API Client
18+
19+
To obtain your access token and refresh tokens, [follow this guide](https://developers.google.com/identity/protocols/oauth2/web-server#top_of_page).
20+
21+
For future reference, I obtained the authorization grant (code), by browsing:
22+
23+
```sh
24+
https://accounts.google.com/o/oauth2/v2/auth?client_id=CLIENT_ID&scope=https://www.googleapis.com/auth/gmail.readonly&response_type=code&access_type=offline&redirect_uri=http://localhost
2325
```
26+
27+
and exchanged the authorisation code for access tokens via a POST request to [oauth2.googleapis.com/token](https://oauth2.googleapis.com):
28+
29+
```sh
30+
curl -X POST "https://oauth2.googleapis.com/token" \
31+
-d client_id=CLIENT_ID \
32+
-d client_secret=CLIENT_SECRET \
33+
-d code=CODE \
34+
-d grant_type=authorization_code \
35+
-d redirect_uri=http://localhost
36+
```
37+
38+
Once you're done, you should have all of the following fields:
39+
40+
```sh
2441
API_KEY [created on the google developer console]
2542
CLIENT_ID [registered on google developer console]
2643
CLIENT_SECRET
2744
EMAIL_ID [which authorized your client, and whose access + refresh tokens you own]
2845
ACCESS_TOKEN
2946
REFRESH_TOKEN
30-
```
31-
You'll only need to do this once because the once you have one access token and the refresh token, you are set. Follow the remaining setps:
47+
```
3248

33-
1. Rename the `config/template` to `config/.env` and replace the first 5 fields with their respective values.
34-
2. Move `data/access_token.json` to `/bin/data/access_token.json` and replace the `<YOUR_ACCESS_TOKEN>` field with the respective value.
49+
Rename the `config/template` to `config/env` and replace the first 5 fields with their respective values.
3550

3651
#### Required Libraries
3752

38-
You'll need the following libraries the `pyfirmata` python library to communicate with the arduino board, and you'll need to flash your arduino with the [standrard firmata](https://github.com/firmata/arduino/blob/master/examples/StandardFirmata/StandardFirmata.ino), firmata is a generic protocol for communicating with microcontrollers from software on a host computer. And you're all set!
53+
- `pyfirmata`
54+
- flash your arduino with the [standrard firmata](https://github.com/firmata/arduino/blob/master/examples/StandardFirmata/StandardFirmata.ino), firmata is a generic protocol for communicating with microcontrollers from software on a host computer.
3955

40-
Connect an LED in the pins mentioned in `gmailLEDControl.py` and run `python gmailLEDControl.py` to start making cURL requests every 2 seconds.
56+
Connect an LED to the pin specified in `gpio_pin_control.py`, and run the python script to make cURL requests every 10 seconds <3

bin/getUnreadEmailCount.sh

-15
This file was deleted.

bin/refreshAccessToken.sh

-8
This file was deleted.

config/template

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
export API_KEY='YOUR_API_KEY'
2-
export EMAIL_ID='GMAIL_WHOSE_ACCESSAND_REFRESH_TOKENS_YOUR_HAVE'
3-
export CLIENT_ID='YOUR_CLIENT_ID'
4-
export CLIENT_SECRET='YOUR_CLIENT_SECRET'
5-
export REFRESH_TOKEN='YOUR_REFRESH_TOKEN'
1+
export API_KEY=''
2+
export EMAIL_ID=''
3+
export CLIENT_ID=''
4+
export CLIENT_SECRET=''
5+
export REFRESH_TOKEN=''
6+
export GRANT_TYPE='refresh_token'
67

7-
export GRANT_TYPE='refresh_token'

count_unread_email.sh

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#! /bin/bash
2+
3+
source "./config/env"
4+
RESP="./data/response.json"
5+
6+
curl "https://gmail.googleapis.com/gmail/v1/users/$EMAIL_ID/messages?q=is:unread&key=$API_KEY" \
7+
-H "Authorization: Bearer $1" \
8+
-H "Accept: application/json" \
9+
--compressed > "$RESP"
10+
11+
IS_ERR=$(grep "code" "$RESP" | cut -d":" -f2 | cut -d"," -f1)
12+
RESULT=$(grep "resultSizeEstimate" "$RESP" | cut -d":" -f2)
13+
14+
if [ "$IS_ERR" ]; then
15+
./refresh_access_token.sh
16+
else
17+
echo "$RESULT"
18+
fi

data/access_token.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
2-
"access_token": "<YOUR_ACCESS_TOKEN>",
2+
"access_token": "YOUR_ACCESS_TOKEN",
33
"expires_in": 3599,
4-
"scope": "https://mail.google.com/",
4+
"scope": "https://www.googleapis.com/auth/gmail.readonly",
55
"token_type": "Bearer"
66
}

gmailLEDControl.py

-15
This file was deleted.

gpio_pin_control.py

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#!/bin/env/python
2+
3+
"Arduino GPIO PIN control with pyfirmata and gmail API"
4+
5+
import os
6+
import json
7+
import time
8+
9+
from pyfirmata import Arduino
10+
11+
class PinController(object):
12+
13+
def __init__(self):
14+
self.board = Arduino('/dev/ttyACM0')
15+
self.pin = 13
16+
17+
def switch_led_state(self, state):
18+
"Controls LED State"
19+
self.board.digital[self.pin].write(state)
20+
21+
def main():
22+
"Main Fucntion"
23+
24+
pcr = PinController()
25+
interval = 10
26+
27+
while True:
28+
token = json.load(open('./data/access_token.json', 'r'))['access_token']
29+
res = os.popen(f'./count_unread_email.sh {token}').read()
30+
print('Total Unread Emails:', res)
31+
32+
if res != '' and int(res):
33+
pcr.switch_led_state(1)
34+
else:
35+
pcr.switch_led_state(0)
36+
37+
time.sleep(interval)
38+
39+
if __name__ == "__main__":
40+
main()

refresh_access_token.sh

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#! /bin/bash
2+
3+
source "./config/env"
4+
5+
curl -X POST \
6+
"https://www.googleapis.com/oauth2/v4/token?" \
7+
-d client_id="$CLIENT_ID" \
8+
-d client_secret="$CLIENT_SECRET" \
9+
-d grant_type="$GRANT_TYPE" \
10+
-d refresh_token="$REFRESH_TOKEN" > ./data/access_token.json
11+

0 commit comments

Comments
 (0)