Pepp Talk - User Guide

Content

Pepp Talk Overview Seeds User Templates Troubleshooting

Pepp Talk Overview

Installing Pepp Talk

Unzip the downloaded PeppTalkProduct.zip to a location of your choice. You will run Pepp Talk from inside this folder. Install the dependencies under the Dependencies section and set up the Apache sever under Preparing your Database with Apache. After you set up Apache, you just have to make one more edit. Go to the PeppTalkProduct folder and open report_generator.sh with your preferred text editor. Change the ABS variable to be the absolute path to this folder. Now that everything is installed, see the Running Pepp Talk section.

Dependencies

Inside the PeppTalkProduct folder is an install.sh Shell Script. Running this script will install all our dependencies for you. However, this may install unnecessary files; for example, our script runs sudo apt-get upgrade, which may install unnecessary files onto your system. If you are concerned with which files are installed on your system, please view the script and select the dependencies you wish to install. Please note however, that our product may not work if you do not install everything in the script.

Do note that if the Linux environment is not running on a Raspberry Pi, sudo rpi-update will fail. This is OK as long as you are not running the Linux environment on a Raspberry Pi. If sudo rpi-update fails and you are running on a Raspberry Pi, please refer to your Raspberry Pi's official documentation on this issue.

Below are the dependencies the script installs. Small descriptions are provided in case apt-get or pip fails and you have to install manually.

sudo apt-get install default-jdk sudo apt-get install python 2.7.6 sudo apt-get install python-pip sudo apt-get install apache2 sudo apt-get install python-dev sudo apt-get install libapache2-mod-wsgi sudo pip install bottle sudo pip install UnQLite sudo apt-get install curl sudo pip install requests sudo pip install datetime sudo apt-get install Cython sudo apt-get install festival sudo apt-get install vlc

We are no longer using Beautiful Soup 4, a web scraping tool. You may still want to install Beautiful Soup 4 for use in your own Seeds. To do so, use:

sudo pip install beautifulsoup4

Preparing Your Database with Apache

The PeppTalk Database wrapper is designed to run as a webservice.
You can use your favorite way of hosting Python WSGI files to host it.
Here we describe the way to deploy it so that it is configured to work with the example applications we have provided.
These instructions are designed for a Debian based box (like Raspbian or Ubuntu)

The PeppTalk Database wrapper requires several dependencies.

Application Dependencies

If you are not using apt-get as your package manager, install these dependencies with your package manager of choice.

Run:
sudo apt-get install apache2
sudo apt-get install python-dev
sudo apt-get install libapache2-mod-wsgi
sudo apt-get install cython
sudo apt-get install python-pip
sudo pip install bottle
sudo pip install UnQLite
sudo apt-get install curl

Note that the capitalization matters for UnQLite.

Configuring Apache

We will make minimal changes to apache from its default configuration.

  1. Check if apache is running by typing:
  2. > curl localhost:80
    Running this command should display a default web page. For example, you might see the following: 
    <html> <body> <h1>It works!</h1> <p>This is the default web page for this server.</p> <p>The web server software is running but no content has been added, yet.</p> </body> </html>
  3. Navigate to the apache home directory.
    This command should by default be cd /etc/apache2/
    This folder has a bunch of conf files and other things. We will change ports.conf and the provided default site.
    If you run your own server, you will probably want to set up the page as a seperate site.
  4. You can use the test editor of your choice to edit ports.conf such as nano
    make sure to edit this file using sudo because the file is read only

  5. Edit ports.conf
  6. Find the lines that says

    NameVirtualHost *:80
    Listen 80

    and replace 80 with 43508. You can use any port you wish, as long as you keep the other componets of Pepp Talk up to date.
    If NameVirtualHost does not exist add it in with port 43508

  7. Navigate into etc/apache2/sites-enabled
  8. Use your prefered text editor to edit the default site.
    It is probably called 000-default.
    Again make sure to edit this file with sudo.
    In that file, within the virtual host tags, add this in the file:

        WSGIScriptAlias /PeppTalk /var/www/pepptalk/app.wsgi
    
        <Directory /var/www/pepptalk>
            WSGIProcessGroup test
            WSGIApplicationGroup %{GLOBAL}
            Order deny,allow
            Allow from all
        </Directory>

    Also change the tag <VirtualHost *:80> at the top of the file by replacing 80 with 43508

    This will serve the pepptalk app WSGI to the /PeppTalk/ extension of your server URL.

  9. Return to the main apache2 directory.
  10. Open up apache.conf in a text editor (remember to use sudo).

    Near the bottom of apache2.conf, above Include sites-enabled/
    add the following line to the file:

    WSGIDaemonProcess test

    Now that apache is configured to serve the WSGI, we need to place the python package and create the WSGI file to serve it.

Placing Python Packages

  1. cd /var/www
  2. sudo mkdir pepptalk
  3. sudo chmod 777 pepptalk because we need to make sure the apache user is able to access our files.
  4. Copy the DatabaseWrapper folder provided in the pepp talk download into /var/www/pepptalk.
    Note you might have to be a super user to add this folder to pepptalk so find where the database wrapper is and run
    sudo cp -r DatabaseWrapper /var/www/pepptalk
  5. sudo chmod 777 DatabaseWrapper
    Now that the package is in place, we just need to create the WSGI file that will interact with Mod_WSGI

Creating WSGI File

  1. create the file app.wsgi in the pepptalk folder. Add the following:
  2. import sys
    
    sys.path.insert(0,"/var/www/pepptalk/DatabaseWrapper")
    
    from pepp_wsgi import application
  3. chmod 777 app.wsgi

  4. sudo service apache2 restart

    This restarts your server (which we want, since we have edited some config files).
  5. curl -H "Content-Type: application/json" -X POST -d '{"name":"weather"}' localhost:43508/PeppTalk/Seeds/

Congratulations, your listening server is now configured!

You may start your Apache server at anytime using

and stop your Apache server using

Running Pepp Talk

In order to run Pepp Talk, you must have information inside the Database, populated using Seeds, and a User Template file. For more information on creating Seeds, see the Seeds section. For more information on User Templates, see the User Templates section. Once you have data in the database, locate the .template file you would like to use to generate your Pepp Talk, and pass its path into the report_generator.sh Shell Script. This path can be a local path or an absolute path. An example of passing in a template to the script is:

./report_generator.sh Template/Weather.template

VLC will open and play your Pepp Talk .wav file after your Pepp Talk is generated (and then VLC will close after the .wav file finishes playing), and if you have a default audio output device connected you should be hearing your Pepp Talk as well. If a .wav file does not play, an error may have occurred, but check that you have a default audio output device connected.

After running Pepp Talk, the .txt and .wav outputs will be in the same location as the User Template.

Admin Mode - Accessing the Database Directly

Inside the DatabaseWrapper folder is the wrapper.py script. Inside this script is a bunch of methods to access the database directly. In order to use these methods, implement this class in a new Python script and add a main method that uses the methods in wrapper.py to do your bidding to the Database. See wrapper.py for more details.

NOTE: Do not attempt to directly modify the Database while the Apache server is running.

Seeds

Seeds are scripts are written to gather data from various sources to be fed into a Pepp Talk. These Seeds can be written in any language and communicate with the database through the REST API.

The Seeds Folder

The Seeds folder contains an example folder that contains scripts that pull various different data sources like weather, finances, IoT devices, and news. These scripts gather the data and send it to the database. These serve as good examples of how to create a Seed for the Pepp Talk system.

Picking a Programming Language

Pepp Talk is designed to have Seeds written in various different languages. We recommend using Python, as our example scripts are written in Python.

Understanding the Database Processing API "REST"

Add Data from the Seed with Name $Name$ to the database

If $Name$ does not exist, this method will fail with a 303 response telling the user to create the method first.

We are adding data $D1$ to Seed $Name$, which was retrieved at time $T1$. The data, $D1$ is a nested JSON document that the user must know the structure of to create the report generator.

Post /PeppTalk/Seeds/$Name$

{
    "data": $D1$,
    "name": $Name1$,
    "timestamp": $T1$
}

The database will return the JSON object passed in.

Retrieve a List of Seeds from the Database

If $Name$, $Name2$, and $Name3$ are stored in the database, the below will be returned from the call below. No data is expected on the call. If the database is empty, a 204 (No Content) will be returned.

Get /PeppTalk/Seeds

Will return

{
    "name": [$Name$, $Name2$, $Name3$]
}

Retrieve the data stored by a Seed

If $D1$ is data associated with Seed $Name1$, the below will be returned for the call, with $T2$ as the time it was entered into the database. Names is a Seed. A request for a non-existent Seed will respond with a 400 (Bad Request) response code.

Get /PeppTalk/Seeds/$Name1

Will return

{
    "data": $D1$,
    "name": $Name1$,
    "timestamp": $T1$,
    "logtimestamp": $T2$
}

Accessing previous data entries

If you wish to access Seed entries in the database other than the most recent, append to the url that retrieves the data (e.g. /PeppTalk/Seeds/$Name1) a forward slash and a number corresponding to how far back in the database you would like to go (i.e. /0 is most recent, /1 is one back, /4 is four back.).

Here is a full example, getting an entry 2 back (the 3rd one) from Seed Name1:

/PeppTalk/Seeds/$Name1/2

Making Repeated Calls to the Database (cron job)

Cron tasks can be scheduled with crontab -e. The crontab takes form

m h dom mon dow command

The first five columns of the crontab are for scheduling how often tasks are run. See the man pages for cron and crontab for more details.

Be aware that the cron daemon runs as a different user, which could require different permissions.

Example Seed

"""
Sample Output for College Park, MD; 3 day forecast
It is mostly cloudy in College Park, MD with a temperature of 62 degrees. Today has a high of 80 and a low of 57.
The forecast for Wednesday is mostly sunny with a high of 71 and a low of 50, Thursday is mostly cloudy with a
high of 75 and a low of 50, Friday is rain with a high of 77 and a low of 62.
"""
 
from seed import Seed
import requests, json
from datetime import datetime
 
class Forecast:
    def __init__(self, location, condition, temp, high, low, daily_forecast):
        self.location = location
        self.condition = condition
        self.temp = temp
        self.high = high
        self.low = low
        self.daily_forecast = daily_forecast
 
    def encode(self):
        encoded = {}
        encoded['location'] = self.location
        encoded['condition'] = self.condition
        encoded['temp'] = self.temp
        encoded['high'] = self.high
        encoded['low'] = self.low
        encoded['forecast'] = []
 
        for day in self.daily_forecast:
            encoded['forecast'].append(day.encode())
 
        return encoded
 
    def __str__(self):
        current = 'It is {} in {} with a temperature of {} degrees. '.format(self.condition, self.location, self.temp)
        today = 'Today has a high of {} and a low of {}. '.format(self.high, self.low)
        weather = ''
 
        forecast_str = []
        for f in self.daily_forecast:
            forecast_str.append(str(f))
 
        if forecast_str:
            weather = 'The forecast for '
            weather += ', '.join(forecast_str)
            weather += "."
 
        return current + today + weather
 
    def __repr__(self):
        return self.__str__()
 
 
class DailyForecast:
    def __init__(self, day, condition, high, low):
        self.day = day
        self.condition = condition
        self.high = high
        self.low = low
 
    def encode(self):
        encoded = {}
        encoded['day'] = self.day
        encoded['condition'] = self.condition
        encoded['high'] = self.high
        encoded['low'] = self.low
        return encoded
 
    def __str__(self):
        return '{} is {} with a high of {} and a low of {}'.format(self.day, self.condition, self.high, self.low)
 
    def __repr__(self):
        return self.__str__()
 
class WeatherSeed():
    dbHost = "http://localhost:43508"
    dbPath = "/PeppTalk/Seeds/"
 
    def __init__(self):
        self.name = "weather"
        self.forecast = None
 
    def retrieve_data(self, location, num):
        print self.name
        if num < 0 or num > 9:
            print "ERROR: Please input the number of days weather forecast you want between 0 and 9."
            return None
 
        if not location:
            print "ERROR: Please input a location."
            return None
 
        baseurl = "https://query.yahooapis.com/v1/public/yql?"
        yql_query = "q=select * from weather.forecast where woeid in (select woeid from geo.places(1) where text=\"{}\")".format(location)
        yql_url = baseurl + yql_query + "&format=json"
        data = requests.get(yql_url).json()
 
        if data['query']['results'] is None:
            print "ERROR: There is no weather forecast for {}".format(location)
            return None
 
        day_dict = {'Mon': 'Monday', 'Tue':'Tuesday', 'Wed':'Wednesday', 'Thu':'Thursday', 'Fri':'Friday', 'Sat':'Saturday', 'Sun':'Sunday'}
        weather = data['query']['results']['channel']['item']
 
        condition = weather['condition']['text'].lower()
        temp = int(weather['condition']['temp'])
        high = int(weather['forecast'][0]['high'])
        low = int(weather['forecast'][0]['low'])
 
        daily_forecast = []
        for day in range(1, num+1):
            day_var = day_dict[weather['forecast'][day]['day']]
            day_condition = weather['forecast'][day]['text'].lower()
            day_high = int(weather['forecast'][day]['high'])
            day_low = int(weather['forecast'][day]['low'])
            day_forecast = DailyForecast(day_var, day_condition, day_high, day_low)
            daily_forecast.append(day_forecast)
 
        forecast = Forecast(location, condition, temp, high, low, daily_forecast)
        self.forecast = forecast
 
    def format_data_for_storage(self):
        weather_json = {}
        if self.forecast:
            weather_json = self.forecast.encode()
        return Seed(self.name, weather_json)
 
    def send_to_database(self, seed):
        weather_json = json.loads(seed.encode())
 
        url = self.dbHost + self.dbPath
        response = requests.post(url, json=weather_json)
        if (response.status_code != 200) and (response.status_code != 201):
            raise RuntimeError(
                'Failed attempt to post to database. Response from ' + url + ' was ' + str(response.    status_code))
 
        url = url+self.name
        response = requests.post(url, json=weather_json)
        if (response.status_code != 200) and (response.status_code != 201):
            raise RuntimeError(
                'Failed attempt to post to database. Response from ' + url + ' was ' + str(response.status_code))
   
            return response
 
    def __str__(self):
        if self.forecast:
            return str(self.forecast)
        else:
            return ""
 
    def __repr__(self):
        return self.__str__()
 
def main():
    location = "College Park, MD"
    weather = WeatherSeed()
    weather.retrieve_data(location, 3)
    seed = weather.format_data_for_storage()
    weather.send_to_database(seed)
 
if __name__ == '__main__':
    main()

User Templates

A User Template is a specially formatted text document that will be translated into a regular text document using the Genshi Templating Engine. It consists of two components: the specially formatted text that the user would like in a report, and a list of the Seeds that this report is pulling information from. User Templates are the instructions that create your very own Pepp Talk A User Template should be saved with the .template extension.

The Templates Folder

The Templates folder is a good place to keep all your User Templates. You do not need to place your User Templates inside this folder (even though we recommend it), as you will be manually passing in the path of a User Template in as a command line argument.

Inside the "Templates" folder is also a sub-folder called "Examples". There you will find several example User Templates that create Pepp Talks using the example Seeds we provided inside the "Seeds" folder. See The Seeds Folder section for more details on these seeds.

Formatting a Template for the Report Generator System

Scripts for our tool are written in a strict subset of the Genshi New Text Template language. The first line is expected to be a Genshi comment, delimited by {# ... #} that contains a list of seeds from which data will be retrieved for use in the template. Each variable in the template is expected to be either an identifier contained in that list, or a retrieval from a dictionary with an identifier contained in that list, with a key corresponding to an entry in the database or a dictionary or key nested within that.

For instance, if the first line is

{# ["weather","finance","openHab"] #}

And the Weather Seed has the fields "location" and "forecast", and "forecast" is a nested structure with the field "hi" and "low", valid variable identifiers would include (non-exhaustively) weather, weather["location"], weather["forecast"], and weather["forecast"]["hi"]. It would not include weather["location"]["hi"]. Errors in variable identifiers will be reported at run-time.

Scripts whose first line lack a list of Seeds are equivalent to scripts whose first line contains an empty list, and will only be valid if they contain no variables.

When you design your own Seeds, you will know their structure and the fields you can call.

How to Use One or Several Completed Templates

In order to use a completed template, you must have information in the database, most likely populated by one or more Seeds. You can use a User Template by passing it to the report_generator.sh Shell Script via command line argument. He is one such example.

./report_generator.sh Template/Weather.template

Example Template

The following is an example User Template for the example weather Seed included with Pepp Talk:

{#["weather"]#}

Hi Kevin,

Currently, the temperature is ${weather['temp']} degrees.

Today's forecast is ${weather['condition']} with a high of ${weather['high']} degrees and low of ${weather['low']} degrees.

{% for forecast in weather['forecast'] %}

${forecast['day']}'s forecast is ${forecast['condition']} with a high of ${forecast['high']} degrees and low of ${forecast['low']} degrees.

{% end %}

Troubleshooting

Hearing the Audio Out

If you are having trouble hearing your Pepp Talk, check that your audio device is connected to your Linux environment, and that the audio device is the Default Audio Output Device.

sudo rpi-update Fails with "command not found"

If the Linux environment is not running on a Raspberry Pi, sudo rpi-update will fail. This is OK as long as you are not running the Linux environment on a Raspberry Pi. If sudo rpi-update fails and you are running on a Raspberry Pi, please refer to your Raspberry Pi's official documentation on this issue.

Pepp Talk cannot find my .template file!

Make sure you have set the absolute path of the PeppTalkProduct folder! Go to the PeppTalkProduct folder and open report_generator.sh with your preferred text editor. Change the ABS variable to be the absolute path to this folder. If you are still having problems, please see the Installing Pepp Talk section.