Viewing entries in
Python

Python: Simple Rest API Example and String Formatting

Python: Simple Rest API Example and String Formatting

Rest API / String Formatting in Python

How did this adventure begin?

My girlfriend has gone on a research trip recently! Normally I wouldn't start my blog posts out that way, however, it's relevant. Her research vessel actually has some data available, publicly, here: http://webcam.oregonstate.edu/tracker/.

There's some cool data there:

  • Temperatures
  • Depth
  • Wind
  • Latitude
  • Longitude

I initially thought this was going to be an endeavor in web parsing, but then I looked at the source of the website. I eventually came across this nifty javascript function they are using:

Particularly handy is the URL: https://app.uhds.oregonstate.edu/api/webcam/ship. I am more familiar with PowerShell than Python, so just to test it out before I learned how to get the data in Python, I used PowerShell to see what data was available.

Initial Data Grab Via PowerShell

This was an extremely simple, yet validating part of the equation.

$url = 'https://app.uhds.oregonstate.edu/api/webcam/ship'
$data = Invoke-RestMethod -Uri $url
$data.count
$data[0]

Sweet! That's what we want. Well, what I was looking for.

Making it work in Python

To make this work in Python, I needed to do a few things.

  • Get the data, preferably as JSON/a dictionary in Python
  • Convert Celsius to Fahrenheit
  • Convert Knots to Mph
  • Format the data and print it out

Getting the Data

For this to work, we need to use the requests library in Python. So the very first line we'll need is:

import requests

To get the data , I built out this function:

def get_data():
    ship_api_url = "https://app.uhds.oregonstate.edu/api/webcam/ship"
    request_data = requests.get(ship_api_url)
    return request_data.json()

First, I start out by storing the URL we used earlier in the variable ship_api_url:

ship_api_url = "https://app.uhds.oregonstate.edu/api/webcam/ship"

Then, I make the request and store the results:

request_data = requests.get(ship_api_url)

And finally, I return the results as a dictionary from the request converted to JSON:

return request_data.json()

I wanted to test out what I had so far, so our script looks like this:

import requests

def get_data():
    ship_api_url = "https://app.uhds.oregonstate.edu/api/webcam/ship"
    request_data = requests.get(ship_api_url)
    return request_data.json()

data = get_data()
print(data[0])

Annnd the results:

Now to get to work!

Converting Values

Now it was time to start converting some of the values. 

I made a function that converts Celsius to Fahrenheit, and then one that converts knots to mph.

First I needed the math:

C to F conversion:

9.0 / 5.0 * temp_in_c + 32

Knots to Mph conversion:

1.1507 * knot

With that in mind, here is the code for the two functions I made:

def convert_c_to_f(temp):
    "Converts Celsius to Fahrenheit."
    conversion = round(9.0 / 5.0 * temp + 32, 2)
    return conversion

def convert_knot_to_mph(knot):
    "Converts wind from knots to mph"
    conversion = round(1.1507 * knot, 2)
    return conversion

I added in some rounding there to ensure we only get up to two decimal places.

String Formatting

The last step for me was to format all of the data, and present it how I wanted it to be presented. To do this I created a function that takes the data and formats it.
It uses a multi line string plus the string format method at the end so I could insert the values that I wanted. 

Here's the function I created for that:

def format_data(data_to_format):
    "Formats the data how we want it"
    formatted = """
    Air Temp [{0} F] Water Temp [{1} F]
    Wind [{2} mph] Depth [{3} meters]
    Lat [{4}] Long [{5}]    
    Current Location: https://www.google.com/maps/place/{4},{5}
    *note* You may need to zoom out on the map to see the relative location!
    """.format(convert_c_to_f(data_to_format['air_temp']),
               convert_c_to_f(data_to_format['water_temp']),
               convert_knot_to_mph(data_to_format['wind']),
               data_to_format['depth'], data_to_format['lat'], data_to_format['lng'])
    return formatted

You can see in the above code snippet that I used the first value of the data array, and for some of the values used the appropriate conversion functions we created earlier.

So what's it look like, now?

Here's all of the current code:

import requests

def get_data():
    "Gets api data"
    ship_api_url = "https://app.uhds.oregonstate.edu/api/webcam/ship"
    request_data = requests.get(ship_api_url)
    return request_data.json()

def convert_c_to_f(temp):
    "Converts Celsius to Fahrenheit."
    conversion = round(9.0 / 5.0 * temp + 32, 2)
    return conversion

def convert_knot_to_mph(knot):
    "Converts wind from knots to mph"
    conversion = round(1.1507 * knot, 2)
    return conversion

def format_data(data_to_format):
    "Formats the data how we want it"
    formatted = """
    Air Temp [{0} F] Water Temp [{1} F]
    Wind [{2} mph] Depth [{3} meters]
    Lat [{4}] Long [{5}]    
    Current Location: https://www.google.com/maps/place/{4},{5}
    *note* You may need to zoom out on the map to see the relative location!
    """.format(convert_c_to_f(data_to_format['air_temp']),
               convert_c_to_f(data_to_format['water_temp']),
               convert_knot_to_mph(data_to_format['wind']),
               data_to_format['depth'], data_to_format['lat'], data_to_format['lng'])
    return formatted

data = get_data()
latest_dataset = data[0]
print(format_data(latest_dataset))

And after running it, here are the results:

Conclusion

I had two goals in doing this. 

  1. Learn a little bit more Python
  2. Make a command for my Python Discord bot that displays the ship's data, as well as the current web cam image (as the website only displayed one OR the other)

I used what we created above, and added a command to my bot which displays the data and the image! Here is the result of that:

Have a question, or know of a different way to achieve the same results? Leave a comment and say hi!

Python: Create a Discord Bot on Your Raspberry Pi Using Discord.py

Python: Create a Discord Bot on Your Raspberry Pi Using Discord.py

Create a Discord Bot on Your Raspberry Pi With Python and Discord.py

This article will get you up and running with a Discord bot on your Raspberry Pi using the Discord.Py library.

Note
The code has been updated to reflect Discord.Py’s re-write.
You can always view latest code, and more examples for this post, here: https://github.com/gngrninja/blog/tree/master/DiscordBotPi

This assumes that you've installed and are using Raspbian.

Table of Contents

If you’d like to check out another programming language, check out my series on getting a C# Discord Bot up and running on a Raspberry Pi!

Create app and invite bot to your server

If you already have a bot token, and a bot invited to your server, you can skip over to updating Raspbian.

1. Navigate to the Discord Developer Console

2. Click "New App"

3. Give it a name, and then click "Create App"

4. Click "Create a Bot User"

5. Keep note of the Token, as you'll need that later.

6. Invite the bot to your server

    a. Use the following URL to invite the bot to your server:
        (Replace your_client_id_goes_here with your bot's client ID)

https://discordapp.com/oauth2/authorize?client_id=your_client_id_goes_here&scope=bot&permissions=0

7. You should now see the bot in your server (offline)

Update Raspbian

First you'll want to ensure your Raspbian installation is up to date. To do this, run the following commands:

1. Update package lists

sudo apt-get update

2. Upgrade packages

sudo apt-get upgrade

3. Clean things up

sudo apt-get dist-upgrade

4. Reboot your Pi!

Install Pre-Requisites for Python 3.7.x and Discord.Py

**Note**

The latest version of Raspbian (10.x/Buster) ships with Python 3.7.x (which should work great with discord.py). 

If you'd like to upgrade your OS to Buster, follow this article.

To check which version you have, run:

cat /etc/os-release
buster.png

If you are running Buster (or Stretch), great! Click here to skip to the next step. Otherwise, continue below.

1. Install libssl-dev (to ensure we can use pip when we install the newest version of Python)

sudo apt-get install libssl-dev
libssl.PNG

2. Install libffi-dev (to ensure audio works with the Discord bot)

sudo apt-get install libffi-dev

3. Install libsqlite3-dev (this will be handy, as it installs libraries needed to install sqlite3 support)

sudo apt-get install libsqlite3-dev

Install Python 3.6.x

1. Grab the latest version of Python 3.x from https://www.python.org/downloads/

wget https://www.python.org/ftp/python/3.6.1/Python-3.6.1.tgz

2. Extract the files, and enter the directory

tar xzvf Python-3.6.0.tgz
tar.PNG
cd Python-3.6.0/

3. Run configure to check for dependencies, and get ready to build the Python installation
(This will take 2-5 minutes)

./configure

4. Run make to start compiling the software
(This will take 15-30 minutes)

make

5. Install Python 3.6.x
(This will take 10-15 minutes)

sudo make install

6. Reboot your Pi!

Install Discory.Py, and get a bot working

NOTE: If you are on a fresh Buster install, you may need to install the following before continuing:

sudo apt install python3-pip
sudo apt install python3-cffi
sudo pip3 install discord.py[voice] 


1. Install latest version of the Discord library for Python (Discord.Py)

sudo python3 -m pip install -U discord.py[voice]

2. Create a bot to test it out

    a. Create directory 

mkdir ~/pipy_bot

    b. Move to that directory

cd ~/pipy_bot

    c. Create an empty file

touch bot.py

    d. Edit the file

nano bot.py

    e. Copy/Paste the following content in the editor (be sure to change your_token_here to your bot's token):

import discord
from discord.ext import commands

TOKEN = ''

description = '''ninjaBot in Python'''
bot = commands.Bot(command_prefix='?', description=description)

@bot.event
async def on_ready():
    print('Logged in as')
    print(bot.user.name)
    print(bot.user.id)
    print('------')


@bot.command()
async def hello(ctx):
    """Says world"""
    await ctx.send("world")


@bot.command()
async def add(ctx, left : int, right : int):
    """Adds two numbers together."""
    await ctx.send(left + right)

bot.run(TOKEN)

    f. Save the file using CTRL+X, and "y"

    g. Run your bot!

python3 bot.py

Test Out Your Bot

1. Go to the Discord server where you've invited your bot to , and try issuing the ?help command

2. Once you verified that works, try the other ones as well!

Have a question or idea? Leave a comment below, or contact me here!

[Back to top]