You can send track all Mastodon posts with a particular hashtag using CircuitPython and your Raspberry Pi Pico W! This example allows you to customise which hashtag you'd like to follow, and then works with the Mastodon API to retrieve toots with that hashtag.
Load the Example and Library
This example requires one external library. Luckily you can load the code and the necessary library together. Click the blue Download Project Bundle button above the code below to download the necessary library and the code.py file in a zip file.
Connect the Raspberry Pi Pico W to your computer via a known good data+power USB A to micro B cable. The Pico W should show up in your File Explorer or Finder (depending on Operating System) as a thumb drive named CIRCUITPY. Extract the contents of the zip file, and copy the entire lib folder, and the code.py file to your CIRCUITPY drive.
Your CIRCUITPY/lib folder should contain the following file:
- adafruit_requests.mpy
Your contents of your CIRCUITPY drive should resemble the following:
# SPDX-FileCopyrightText: 2022 Liz Clark for Adafruit Industries # SPDX-License-Identifier: MIT import os import re import time import ssl import wifi import socketpool import microcontroller import adafruit_requests # enter the hashtag that you want to follow hashtag = "CircuitPython" # connect to SSID wifi.radio.connect(os.getenv('CIRCUITPY_WIFI_SSID'), os.getenv('CIRCUITPY_WIFI_PASSWORD')) # add your mastodon token as 'mastodon_token' to your settings.toml file headers = {'Authorization': 'Bearer ' + os.getenv('mastodon_token') + 'read:statuses'} pool = socketpool.SocketPool(wifi.radio) requests = adafruit_requests.Session(pool, ssl.create_default_context()) # initial request, gets most recent matching hashtag post # add your mastodon instance (mastodon.social, tech.lgbt, etc) # to your settings.toml file as mastodon_host r = requests.get("https://%s/api/v1/timelines/tag/%s?limit=1" % (os.getenv('mastodon_host'), hashtag), headers=headers) # pylint: disable=line-too-long json_data = r.json() post_id = str(json_data[0]['id']) print("A new #%s post from @%s:" % (hashtag, str(json_data[0]['account']['acct']))) print(re.sub('<[^>]+>', '', json_data[0]['content'])) print() while True: try: time.sleep(360) # compares post_id to see if a new post to the hashtag has been found r = requests.get("https://%s/api/v1/timelines/tag/%s?since_id=%s" % (os.getenv('mastodon_host'), hashtag, post_id), headers=headers) # pylint: disable=line-too-long json_data = r.json() json_length = len(json_data) # if the id's match, then the json array is empty (length of 0) # otherwise there is a new post if json_length > 0: post_id = str(json_data[0]['id']) print("A new #%s post from @%s:" % (hashtag, str(json_data[0]['account']['acct']))) print(re.sub('<[^>]+>', '', json_data[0]['content'])) print() else: print("no new #%s posts" % hashtag) print(json_length) print() except Exception as e: # pylint: disable=broad-except print("Error:\n", str(e)) print("Resetting microcontroller in 10 seconds") time.sleep(10) microcontroller.reset()
Add Your settings.toml File
Remember to add your settings.toml file as described in the Create Your settings.toml File page earlier in the guide. You'll need to include your CIRCUITPY_WIFI_SSID
, CIRCUITPY_WIFI_PASSWORD
, mastodon_host
and mastodon_token
in the file.
The mastodon_host
variable should be assigned only the text part of the URL to your Mastodon instance. For example, "mastodon.social"
or "fosstodon.org"
without the https:// or a trailing /.
CIRCUITPY_WIFI_SSID = "your-wifi-ssid-here" CIRCUITPY_WIFI_PASSWORD = "your-wifi-password-here" # Your host should be only the text part of the URL to your Mastodon instance. # For example, "mastodon.social" or "fosstodon.org" without the https://. mastodon_host = "your-mastodon-instance-here" mastodon_token = "your-mastodon-token-here"
Tracking a Hashtag
Once everything is saved to CIRCUITPY, you'll want to connect to the serial console. After a moment, you'll see the latest post that included the #CircuitPython hashtag.
Once the latest post is grabbed, the code will continue to check the hashtag for new posts. If there are no new posts, you'll see the following in the serial console.
When it finds a new post, it will print it to the serial console as it did with the first one.
That's all there is to tracking a hashtag on Mastodon using CircuitPython and the Raspberry Pi Pico W!
Hashtag
At the top of code, you can enter the hashtag that you want to follow as a string. This will be included in your API request URL.
# enter the hashtag that you want to follow hashtag = "CircuitPython"
Headers
Your authentication token is packed into headers
via your settings.toml file. This is included in your API POST request to gain access to your Mastodon account. url
is your API request URL. It passes your Mastodon instance via your settings.toml file.
# add your mastodon token as 'mastodon_token' to your settings.toml file headers = {'Authorization': 'Bearer ' + os.getenv('mastodon_token') + 'read:statuses'}
Initial Request
Before the loop, an initial request is made to the API to access the most recent post with the hashtag that you are tracking. In the URL, your Mastodon instance is passed via your settings.toml file.
The response from the request, is packed into a JSON. From the JSON, the post ID number is tracked as post_id
. This will be used in the loop to see if a new hashtag post has been tooted.
In the REPL, you'll see the hashtag post printed with the account name and the post content. re.sub()
is used to remove extraneous HTML (<
and >
) tags that are included in the raw post text.
# initial request, gets most recent matching hashtag post # add your mastodon instance (mastodon.social, tech.lgbt, etc) to your settings.toml file as mastodon_host r = requests.get("https://%s/api/v1/timelines/tag/%s?limit=1" % (os.getenv('mastodon_host'), hashtag), headers=headers) # pylint: disable=line-too-long json_data = r.json() post_id = str(json_data[0]['id']) print("A new #%s post from @%s:" % (hashtag, str(json_data[0]['account']['acct']))) print(re.sub('<[^>]+>', '', json_data[0]['content'])) print()
The Loop
In the loop, a request is made via the API approximately every 5 minutes to see if a new post with the hashtag has been tooted. post_id
is passed to the ?since_id=
object in the URL. This allows you to see if there is a new post via the API rather than using logic in CircuitPython.
If there a new post has not been tooted, then the request returns an empty JSON. This is checked using the len()
function. If the JSON isn't empty, then the newly tooted post with the hashtag is printed to the REPL and post_id
is updated with the new post ID number.
time.sleep(360) # compares post_id to see if a new post to the hashtag has been found r = requests.get("https://%s/api/v1/timelines/tag/%s?since_id=%s" % (os.getenv('mastodon_host'), hashtag, post_id), headers=headers) # pylint: disable=line-too-long json_data = r.json() json_length = len(json_data) # if the id's match, then the json array is empty (length of 0) # otherwise there is a new post if json_length > 0: post_id = str(json_data[0]['id']) print("A new #%s post from @%s:" % (hashtag, str(json_data[0]['account']['acct']))) print(re.sub('<[^>]+>', '', json_data[0]['content'])) print() else: print("no new #%s posts" % hashtag) print(json_length) print()
Text editor powered by tinymce.