Skip to content

Commit 253d432

Browse files
authored
Merge pull request #765 from dastels/master
Twitter API guide code
2 parents eac551c + 9f916ec commit 253d432

5 files changed

Lines changed: 4367 additions & 0 deletions

File tree

Twitter_API/binascii.py

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
"""
2+
Copied and tweaked from micropython-lib
3+
"""
4+
5+
PAD = '='
6+
7+
#pylint:disable=invalid-name,line-too-long
8+
table_a2b_base64 = b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff>\xff\xff\xff?456789:;<=\xff\xff\xff\xff\xff\xff\xff\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\xff\xff\xff\xff\xff\xff\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&\'()*+,-./0123\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'
9+
#pylint:enable=line-too-long
10+
11+
assert len(table_a2b_base64) == 256
12+
13+
def a2b_base64(ascii_data):
14+
"Decode a line of base64 data."
15+
16+
res = []
17+
quad_pos = 0
18+
leftchar = 0
19+
leftbits = 0
20+
last_char_was_a_pad = False
21+
22+
for c in ascii_data:
23+
c = chr(c)
24+
if c == PAD:
25+
if quad_pos > 2 or (quad_pos == 2 and last_char_was_a_pad):
26+
break # stop on 'xxx=' or on 'xx=='
27+
last_char_was_a_pad = True
28+
else:
29+
n = ord(table_a2b_base64[ord(c)])
30+
if n == 0xff:
31+
continue # ignore strange characters
32+
#
33+
# Shift it in on the low end, and see if there's
34+
# a byte ready for output.
35+
quad_pos = (quad_pos + 1) & 3
36+
leftchar = (leftchar << 6) | n
37+
leftbits += 6
38+
#
39+
if leftbits >= 8:
40+
leftbits -= 8
41+
res.append((leftchar >> leftbits).to_bytes(1, 'big'))
42+
leftchar &= ((1 << leftbits) - 1)
43+
#
44+
last_char_was_a_pad = False
45+
else:
46+
if leftbits != 0:
47+
raise Exception("Incorrect padding")
48+
49+
return b''.join(res)
50+
51+
# ____________________________________________________________
52+
53+
table_b2a_base64 = (
54+
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/")
55+
56+
def b2a_base64(bin_data):
57+
"Base64-code line of data."
58+
59+
newlength = (len(bin_data) + 2) // 3
60+
newlength = newlength * 4 + 1
61+
res = []
62+
63+
leftchar = 0
64+
leftbits = 0
65+
for c in bin_data:
66+
# Shift into our buffer, and output any 6bits ready
67+
leftchar = (leftchar << 8) | c
68+
leftbits += 8
69+
res.append(table_b2a_base64[(leftchar >> (leftbits-6)) & 0x3f])
70+
leftbits -= 6
71+
if leftbits >= 6:
72+
res.append(table_b2a_base64[(leftchar >> (leftbits-6)) & 0x3f])
73+
leftbits -= 6
74+
#
75+
if leftbits == 2:
76+
res.append(table_b2a_base64[(leftchar & 3) << 4])
77+
res.append(PAD)
78+
res.append(PAD)
79+
elif leftbits == 4:
80+
res.append(table_b2a_base64[(leftchar & 0xf) << 2])
81+
res.append(PAD)
82+
return ''.join(res).encode('ascii')

Twitter_API/code.py

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
"""
2+
Halloween countdown for PyPortal.
3+
4+
Adafruit invests time and resources providing this open source code.
5+
Please support Adafruit and open source hardware by purchasing
6+
products from Adafruit!
7+
8+
Written by Dave Astels for Adafruit Industries
9+
Copyright (c) 2019 Adafruit Industries
10+
Licensed under the MIT license.
11+
12+
All text above must be included in any redistribution.
13+
"""
14+
15+
#pylint:disable=invalid-name
16+
import time
17+
import binascii
18+
import json
19+
import board
20+
from adafruit_pyportal import PyPortal
21+
import adafruit_esp32spi.adafruit_esp32spi_requests as requests
22+
23+
username = 'codewisdom'
24+
25+
try:
26+
from secrets import secrets
27+
except ImportError:
28+
print("""WiFi settings are kept in secrets.py, please add them there!
29+
the secrets dictionary must contain 'ssid' and 'password' at a minimum""")
30+
raise
31+
32+
def halt_and_catch_fire(message, *args):
33+
"""Log a critical error and stall the system."""
34+
print(message % args)
35+
while True:
36+
pass
37+
38+
def get_bearer_token():
39+
"""Get the bearer authentication token from twitter."""
40+
raw_key = secrets['twitter_api_key'] + ':' + secrets['twitter_secret_key']
41+
encoded_key = binascii.b2a_base64(bytes(raw_key, 'utf8'))
42+
string_key = bytes.decode(encoded_key)
43+
headers = {'Authorization': 'Basic ' + string_key,
44+
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'}
45+
response = requests.post('https://api.twitter.com/oauth2/token',
46+
headers=headers,
47+
data='grant_type=client_credentials')
48+
response_dict = json.loads(response.content)
49+
if response_dict['token_type'] != 'bearer':
50+
halt_and_catch_fire('Wrong token type from twitter: %s', response_dict['token_type'])
51+
return response_dict['access_token']
52+
53+
# determine the current working directory
54+
# needed so we know where to find files
55+
cwd = ("/"+__file__).rsplit('/', 1)[0]
56+
url = 'https://api.twitter.com/1.1/statuses/user_timeline.json?count=1&screen_name=' + username
57+
58+
59+
# Initialize the pyportal object and let us know what data to fetch and where
60+
# to display it
61+
pyportal = PyPortal(url=url,
62+
json_path=(0, 'text'),
63+
status_neopixel=board.NEOPIXEL,
64+
default_bg=cwd + '/twitter_background.bmp',
65+
# external_spi=spi,
66+
# esp=esp,
67+
text_font=cwd+'/fonts/Helvetica-Bold-16.bdf',
68+
text_position=(20, 60),
69+
text_color=0xFFFFFF,
70+
text_wrap=35,
71+
caption_text='@' + username,
72+
caption_font=cwd+'/fonts/Helvetica-Bold-16.bdf',
73+
caption_position=(5, 210),
74+
caption_color=0x808080)
75+
76+
bearer_token = get_bearer_token()
77+
78+
pyportal.set_headers({'Authorization': 'Bearer ' + bearer_token})
79+
80+
while True:
81+
pyportal.fetch()
82+
time.sleep(3600) # check every hour

0 commit comments

Comments
 (0)