This guide is obsolete. See our guides for AirLift for current WiFi co-processor hardware and software: https://learn.adafruit.com/search?q=airlift

One of the powers of Python is the built-in data parsing capabilities. Stuff that's really hard in C, like json parsing, comes with the larger builds of CircuitPython, making it really easy to get IoT projects going.

For example, we can connect to internet API's and parse out the data we want very fast.

In this demo, we'll use the coinbase API for the current Bitcoin pricing. This is one of the few API's we found that doesn't require a key, so it's very fast to test and use.

You can check the output by visiting http://api.coindesk.com/v1/bpi/currentprice.json and seeing the output, which will look something like

{"time":{"updated":"Dec 16, 2018 22:43:00 UTC","updatedISO":"2018-12-16T22:43:00+00:00","updateduk":"Dec 16, 2018 at 22:43 GMT"},"disclaimer":"This data was produced from the CoinDesk Bitcoin Price Index (USD). Non-USD currency data converted using hourly conversion rate from openexchangerates.org","chartName":"Bitcoin","bpi":{"USD":{"code":"USD","symbol":"$","rate":"3,227.6983","description":"United States Dollar","rate_float":3227.6983},"GBP":{"code":"GBP","symbol":"£","rate":"2,561.0302","description":"British Pound Sterling","rate_float":2561.0302},"EUR":{"code":"EUR","symbol":"€","rate":"2,855.5609","description":"Euro","rate_float":2855.5609}}}

You can explore this data to see exactly where the info you want is, using tools like http://jsonviewer.stack.hu/ (there's plenty of these kinds of sites, just search for a 'json viewer' or 'json explorer')

After pasting in the JSON data

You can navigate through it.

So for example, the USD conversion data is in bpi->USB->rate_float

In our code, once we get the URL data response, we can parse it and extract that entry with bitcoin = json["bpi"]["USD"]["rate_float"]

Here's the full example. Note we use a try block for json parsing in case the data comes back to us weird or its somehow not valid json data.

"""
This example will access an API, grab a number like hackaday skulls, github
stars, price of bitcoin, twitter followers... if you can find something that
spits out JSON data, we can display it!
"""
import gc
import time
import board
import busio
from digitalio import DigitalInOut
from digitalio import Direction
import neopixel
import adafruit_espatcontrol.adafruit_espatcontrol_socket as socket
from adafruit_espatcontrol import adafruit_espatcontrol
from adafruit_ht16k33 import segments
import adafruit_requests as requests

# Get wifi details and more from a secrets.py file
try:
    from secrets import secrets
except ImportError:
    print("WiFi secrets are kept in secrets.py, please add them there!")
    raise

#              CONFIGURATION
PLAY_SOUND_ON_CHANGE = False
NEOPIXELS_ON_CHANGE = False
TIME_BETWEEN_QUERY = 60  # in seconds

# Some data sources and JSON locations to try out

# Bitcoin value in USD
DATA_SOURCE = "http://api.coindesk.com/v1/bpi/currentprice.json"
DATA_LOCATION = ["bpi", "USD", "rate_float"]

# Github stars! You can query 1ce a minute without an API key token
# DATA_SOURCE = "https://api.github.com/repos/adafruit/circuitpython"
# if 'github_token' in secrets:
#    DATA_SOURCE += "?access_token="+secrets['github_token']
# DATA_LOCATION = ["stargazers_count"]

# Youtube stats
# CHANNEL_ID = "UCpOlOeQjj7EsVnDh3zuCgsA" # this isn't a secret but you have to look it up
# DATA_SOURCE = "https://www.googleapis.com/youtube/v3/channels/?part=statistics&id=" \
#              + CHANNEL_ID +"&key="+secrets['youtube_token']
# try also 'viewCount' or 'videoCount
# DATA_LOCATION = ["items", 0, "statistics", "subscriberCount"]


# Subreddit subscribers
# DATA_SOURCE = "https://www.reddit.com/r/circuitpython/about.json"
# DATA_LOCATION = ["data", "subscribers"]

# Hackaday Skulls (likes), requires an API key
# DATA_SOURCE = "https://api.hackaday.io/v1/projects/1340?api_key="+secrets['hackaday_token']
# DATA_LOCATION = ["skulls"]

# Twitter followers
# DATA_SOURCE = "https://cdn.syndication.twimg.com/widgets/followbutton/info.json?" + \
# "screen_names=adafruit"
# DATA_LOCATION = [0, "followers_count"]


# With a Particle Argon
RX = board.ESP_TX
TX = board.ESP_RX
resetpin = DigitalInOut(board.ESP_WIFI_EN)
rtspin = DigitalInOut(board.ESP_CTS)
uart = busio.UART(TX, RX, timeout=0.1)
esp_boot = DigitalInOut(board.ESP_BOOT_MODE)
esp_boot.direction = Direction.OUTPUT
esp_boot.value = True


# Create the connection to the co-processor and reset
esp = adafruit_espatcontrol.ESP_ATcontrol(
    uart, 115200, run_baudrate=921600, reset_pin=resetpin, rts_pin=rtspin, debug=False
)
esp.hard_reset()

requests.set_socket(socket, esp)

# Create the I2C interface.
i2c = busio.I2C(board.SCL, board.SDA)
# Attach a 7 segment display and display -'s so we know its not live yet
display = segments.Seg7x4(i2c)
display.print("----")

# neopixels
if NEOPIXELS_ON_CHANGE:
    pixels = neopixel.NeoPixel(board.A1, 16, brightness=0.4, pixel_order=(1, 0, 2, 3))
    pixels.fill(0)

# music!
if PLAY_SOUND_ON_CHANGE:
    import audioio

    wave_file = open("coin.wav", "rb")
    wave = audioio.WaveFile(wave_file)

# we'll save the value in question
last_value = value = None
the_time = None
times = 0


def chime_light():
    """Light up LEDs and play a tune"""
    if NEOPIXELS_ON_CHANGE:
        for i in range(0, 100, 10):
            pixels.fill((i, i, i))
    if PLAY_SOUND_ON_CHANGE:
        with audioio.AudioOut(board.A0) as audio:
            audio.play(wave)
            while audio.playing:
                pass
    if NEOPIXELS_ON_CHANGE:
        for i in range(100, 0, -10):
            pixels.fill((i, i, i))
        pixels.fill(0)


while True:
    try:
        while not esp.is_connected:
            # secrets dictionary must contain 'ssid' and 'password' at a minimum
            esp.connect(secrets)

        the_time = esp.sntp_time

        # great, lets get the data
        print("Retrieving data source...", end="")
        r = requests.get(DATA_SOURCE)
        print("Reply is OK!")
    except (ValueError, RuntimeError, adafruit_espatcontrol.OKError) as e:
        print("Failed to get data, retrying\n", e)
        continue
    # print('-'*40,)
    # print("Headers: ", r.headers)
    # print("Text:", r.text)
    # print('-'*40)

    value = r.json()
    for x in DATA_LOCATION:
        value = value[x]
    if not value:
        continue
    print(times, the_time, "value:", value)
    display.print(int(value))

    if last_value != value:
        chime_light()  # animate the neopixels
        last_value = value
    times += 1

    # normally we wouldn't have to do this, but we get bad fragments
    r = value = None
    gc.collect()
    print(gc.mem_free())  # pylint: disable=no-member
    time.sleep(TIME_BETWEEN_QUERY)

To display it, we use a 7-segment display hooked up to the I2C port, such as this one:

What's better than a single LED? Lots of LEDs! A fun way to make a small display is to use an 8x8 matrix or a
Out of Stock

Or the all-in-one FeatherWing:

One segment? No way dude! 7-Segments for life!This is the Green Adafruit 0.56" 4-Digit 7-Segment Display w/ FeatherWing Combo Pack! We also have these...
Out of Stock

This guide was first published on Dec 16, 2018. It was last updated on Dec 16, 2018.

This page (AT: Bitcoin Price Demo) was last updated on Nov 06, 2020.