Skip to content

Commit e1766b0

Browse files
committed
Update Twitch API Example with Connection Manager
1 parent 7106d2f commit e1766b0

File tree

1 file changed

+99
-83
lines changed

1 file changed

+99
-83
lines changed
Lines changed: 99 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,49 @@
1-
# SPDX-FileCopyrightText: 2023 DJDevon3
1+
# SPDX-FileCopyrightText: 2024 DJDevon3
22
# SPDX-License-Identifier: MIT
33
# Coded for Circuit Python 8.2.x
4-
# Twitch_API_Example
4+
"""Twitch API Example"""
5+
# pylint: disable=import-error
56

67
import os
7-
import ssl
88
import time
99

10-
import socketpool
10+
import adafruit_connection_manager
1111
import wifi
1212

1313
import adafruit_requests
1414

15-
# Initialize WiFi Pool (There can be only 1 pool & top of script)
16-
pool = socketpool.SocketPool(wifi.radio)
17-
1815
# Twitch Developer Account & oauth App Required:
1916
# Visit https://dev.twitch.tv/console to create an app
20-
21-
# Ensure these are in secrets.py or settings.toml
22-
# "Twitch_ClientID": "Your Developer APP ID Here",
23-
# "Twitch_Client_Secret": "APP ID secret here",
24-
# "Twitch_UserID": "Your Twitch UserID here",
17+
# Ensure these are in settings.toml
18+
# TWITCH_CLIENT_ID = "Your Developer APP ID Here"
19+
# TWITCH_CLIENT_SECRET = "APP ID secret here"
20+
# TWITCH_USER_ID = "Your Twitch UserID here"
2521

2622
# Get WiFi details, ensure these are setup in settings.toml
2723
ssid = os.getenv("CIRCUITPY_WIFI_SSID")
2824
password = os.getenv("CIRCUITPY_WIFI_PASSWORD")
29-
twitch_client_id = os.getenv("Twitch_ClientID")
30-
twitch_client_secret = os.getenv("Twitch_Client_Secret")
25+
TWITCH_CID = os.getenv("TWITCH_CLIENT_ID")
26+
TWITCH_CS = os.getenv("TWITCH_CLIENT_SECRET")
3127
# For finding your Twitch User ID
3228
# https://www.streamweasels.com/tools/convert-twitch-username-to-user-id/
33-
twitch_user_id = os.getenv("Twitch_UserID") # User ID you want endpoints from
29+
TWITCH_UID = os.getenv("TWITCH_USER_ID")
3430

35-
# Time between API refreshes
31+
# API Polling Rate
3632
# 900 = 15 mins, 1800 = 30 mins, 3600 = 1 hour
37-
sleep_time = 900
33+
SLEEP_TIME = 900
34+
35+
# Set DEBUG to True for full JSON response.
36+
# STREAMER WARNING: Credentials will be viewable
37+
DEBUG = False
38+
39+
# Initalize Wifi, Socket Pool, Request Session
40+
pool = adafruit_connection_manager.get_radio_socketpool(wifi.radio)
41+
ssl_context = adafruit_connection_manager.get_radio_ssl_context(wifi.radio)
42+
requests = adafruit_requests.Session(pool, ssl_context)
3843

3944

40-
# Converts seconds to minutes/hours/days
4145
def time_calc(input_time):
46+
"""Converts seconds to minutes/hours/days"""
4247
if input_time < 60:
4348
return f"{input_time:.0f} seconds"
4449
if input_time < 3600:
@@ -48,42 +53,44 @@ def time_calc(input_time):
4853
return f"{input_time / 60 / 60 / 24:.1f} days"
4954

5055

56+
def _format_datetime(datetime):
57+
"""F-String formatted struct time conversion"""
58+
return (
59+
f"{datetime.tm_mon:02}/"
60+
+ f"{datetime.tm_mday:02}/"
61+
+ f"{datetime.tm_year:02} "
62+
+ f"{datetime.tm_hour:02}:"
63+
+ f"{datetime.tm_min:02}:"
64+
+ f"{datetime.tm_sec:02}"
65+
)
66+
67+
5168
# First we use Client ID & Client Secret to create a token with POST
5269
# No user interaction is required for this type of scope (implicit grant flow)
5370
twitch_0auth_header = {"Content-Type": "application/x-www-form-urlencoded"}
5471
TWITCH_0AUTH_TOKEN = "https://id.twitch.tv/oauth2/token"
5572

56-
# Connect to Wi-Fi
57-
print("\n===============================")
58-
print("Connecting to WiFi...")
59-
requests = adafruit_requests.Session(pool, ssl.create_default_context())
60-
while not wifi.radio.connected:
61-
try:
62-
wifi.radio.connect(ssid, password)
63-
except ConnectionError as e:
64-
print("Connection Error:", e)
65-
print("Retrying in 10 seconds")
66-
time.sleep(10)
67-
print("Connected!\n")
68-
6973
while True:
74+
# Connect to Wi-Fi
75+
print("\nConnecting to WiFi...")
76+
while not wifi.radio.ipv4_address:
77+
try:
78+
wifi.radio.connect(ssid, password)
79+
except ConnectionError as e:
80+
print("❌ Connection Error:", e)
81+
print("Retrying in 10 seconds")
82+
print("✅ Wifi!")
83+
7084
try:
71-
# ----------------------------- POST FOR BEARER TOKEN -----------------------
72-
print(
73-
"Attempting Bearer Token Request!"
74-
) # ---------------------------------------
75-
# Print Request to Serial
76-
debug_bearer_request = (
77-
False # STREAMER WARNING: your client secret will be viewable
78-
)
79-
if debug_bearer_request:
80-
print("Full API GET URL: ", TWITCH_0AUTH_TOKEN)
81-
print("===============================")
85+
# ------------- POST FOR BEARER TOKEN -----------------
86+
print(" | Attempting Bearer Token Request!")
87+
if DEBUG:
88+
print(f"Full API GET URL: {TWITCH_0AUTH_TOKEN}")
8289
twitch_0auth_data = (
8390
"&client_id="
84-
+ twitch_client_id
91+
+ TWITCH_CID
8592
+ "&client_secret="
86-
+ twitch_client_secret
93+
+ TWITCH_CS
8794
+ "&grant_type=client_credentials"
8895
)
8996

@@ -95,70 +102,79 @@ def time_calc(input_time):
95102
twitch_0auth_json = twitch_0auth_response.json()
96103
twitch_access_token = twitch_0auth_json["access_token"]
97104
except ConnectionError as e:
98-
print("Connection Error:", e)
105+
print(f"Connection Error: {e}")
99106
print("Retrying in 10 seconds")
107+
print(" | 🔑 Token Authorized!")
100108

101-
# Print Response to Serial
102-
debug_bearer_response = (
103-
False # STREAMER WARNING: your client secret will be viewable
104-
)
105-
if debug_bearer_response:
106-
print("JSON Dump: ", twitch_0auth_json)
107-
print("Header: ", twitch_0auth_header)
108-
print("Access Token: ", twitch_access_token)
109+
# STREAMER WARNING: your client secret will be viewable
110+
if DEBUG:
111+
print(f"JSON Dump: {twitch_0auth_json}")
112+
print(f"Header: {twitch_0auth_header}")
113+
print(f"Access Token: {twitch_access_token}")
109114
twitch_token_type = twitch_0auth_json["token_type"]
110-
print("Token Type: ", twitch_token_type)
115+
print(f"Token Type: {twitch_token_type}")
111116

112-
print("Board Uptime: ", time_calc(time.monotonic()))
113117
twitch_token_expiration = twitch_0auth_json["expires_in"]
114-
print("Token Expires in: ", time_calc(twitch_token_expiration))
118+
print(f" | Token Expires in: {time_calc(twitch_token_expiration)}")
115119

116-
# ----------------------------- GET DATA -------------------------------------
120+
# ----------------------------- GET DATA --------------------
117121
# Bearer token is refreshed every time script runs :)
118122
# Twitch sets token expiration to about 64 days
119123
# Helix is the name of the current Twitch API
120124
# Now that we have POST bearer token we can do a GET for data
121-
# ----------------------------------------------------------------------------
125+
# -----------------------------------------------------------
122126
twitch_header = {
123127
"Authorization": "Bearer " + twitch_access_token + "",
124-
"Client-Id": "" + twitch_client_id + "",
128+
"Client-Id": "" + TWITCH_CID + "",
125129
}
126130
TWITCH_FOLLOWERS_SOURCE = (
127131
"https://api.twitch.tv/helix/channels"
128132
+ "/followers?"
129133
+ "broadcaster_id="
130-
+ twitch_user_id
134+
+ TWITCH_UID
131135
)
132-
print(
133-
"\nAttempting to GET TWITCH Stats!"
134-
) # ------------------------------------------------
135-
print("===============================")
136-
twitch_followers_response = requests.get(
136+
print(" | Attempting to GET Twitch JSON!")
137+
twitch_response = requests.get(
137138
url=TWITCH_FOLLOWERS_SOURCE, headers=twitch_header
138139
)
139140
try:
140-
twitch_followers_json = twitch_followers_response.json()
141+
twitch_json = twitch_response.json()
141142
except ConnectionError as e:
142-
print("Connection Error:", e)
143+
print(f"Connection Error: {e}")
143144
print("Retrying in 10 seconds")
144145

145-
# Print Response to Serial
146-
debug_bearer_response = (
147-
False # STREAMER WARNING: your bearer token will be viewable
148-
)
149-
if debug_bearer_response:
150-
print("Full API GET URL: ", TWITCH_FOLLOWERS_SOURCE)
151-
print("Header: ", twitch_header)
152-
print("JSON Full Response: ", twitch_followers_json)
153-
154-
twitch_followers = twitch_followers_json["total"]
155-
print("Followers: ", twitch_followers)
156-
print("Finished!")
157-
print("Next Update in: ", time_calc(sleep_time))
146+
if DEBUG:
147+
print(f" | Full API GET URL: {TWITCH_FOLLOWERS_SOURCE}")
148+
print(f" | Header: {twitch_header}")
149+
print(f" | JSON Full Response: {twitch_json}")
150+
151+
if "status" in twitch_json:
152+
twitch_error_status = twitch_json["status"]
153+
print(f"❌ Status: {twitch_error_status}")
154+
155+
if "error" in twitch_json:
156+
twitch_error = twitch_json["error"]
157+
print(f"❌ Error: {twitch_error}")
158+
159+
if "message" in twitch_json:
160+
twitch_error_msg = twitch_json["message"]
161+
print(f"❌ Message: {twitch_error_msg}")
162+
163+
if "total" in twitch_json:
164+
print(" | ✅ Twitch JSON!")
165+
twitch_followers = twitch_json["total"]
166+
print(f" | | Followers: {twitch_followers}")
167+
168+
twitch_response.close()
169+
print("✂️ Disconnected from Twitch API")
170+
171+
print("\nFinished!")
172+
print(f"Board Uptime: {time_calc(time.monotonic())}")
173+
print(f"Next Update: {time_calc(SLEEP_TIME)}")
158174
print("===============================")
159175

160176
except (ValueError, RuntimeError) as e:
161-
print("Failed to get data, retrying\n", e)
177+
print(f"Failed to get data, retrying\n {e}")
162178
time.sleep(60)
163-
continue
164-
time.sleep(sleep_time)
179+
break
180+
time.sleep(SLEEP_TIME)

0 commit comments

Comments
 (0)