Park Life
Free music and movies in Minneapolis
parks via text messaging
Image credit: http://linden-hills.com/
Text
What is this?
An application that responds to text messages by sending information about free music and movie events in Minneapolis parks.
Text FUN to (763) 273-5353
Tools used:
- Python
- Google App Engine
- Google Cloud Datastore
- Twilio
- Python libraries
flask, icalendar, pytz
Creating the project
-
Click on "Create Project"
-
Select "Try App Engine"
-
Download the sample project
-
Install the Google SDK if needed
Getting the data
- Download calendar from Minneapolis Parks website
- Convert from iCalendar format to JSON
from json import JSONEncoder
import json
from datetime import datetime
from icalendar import Calendar, vDDDTypes, Event
class ICalendarEncoder(JSONEncoder):
def default(self, obj, markers=None):
try:
if obj.__module__.startswith("icalendar.prop"):
return (obj.to_ical())
except AttributeError:
pass
if isinstance(obj, datetime):
return (obj.now().strftime('%Y-%m-%dT%H:%M:%S'))
return JSONEncoder.default(self,obj)
cal = Calendar.from_ical(open('basic.ics','rb').read())
event_list = []
for event in cal.walk(name="VEVENT"):
suspect = json.dumps(event, cls=ICalendarEncoder)
working = json.loads(suspect)
event_list.append(working)
with open('cal.json', 'w') as f:
cal_js = json.dumps(event_list)
f.write(cal_js)
Creating the data model
# models.py
from google.appengine.ext import ndb
class Event(ndb.Model):
summary = ndb.StringProperty()
description = ndb.StringProperty()
start = ndb.StringProperty()
end = ndb.StringProperty()
date = ndb.StringProperty()
location = ndb.StringProperty()
uid = ndb.StringProperty()
Loading into a database
# load.py
from flask import Flask
app = Flask(__name__)
app.config['DEBUG'] = True
import json
from models import Event
from util import utc_to_central, time_to_string
@app.route('/load')
def load():
with open('cal.json') as f:
events = json.load(f)
for data in events:
if 'RRULE' in data: # Recurring event
continue
start = utc_to_central(data['DTSTART'])
end = utc_to_central(data['DTEND'])
date = "%d%02d%02d" % (start.year, start.month, start.day)
start_time = time_to_string(start)
end_time = time_to_string(end)
event = Event(
summary = data['SUMMARY'].strip(),
description = data['DESCRIPTION'].strip(),
date = date,
start = start_time,
end = end_time,
location = data['LOCATION'].strip(),
uid = data['UID'])
event.put()
return 'OK'
Utility functions
from datetime import datetime
from pytz import timezone
utc = timezone('utc')
central = timezone('US/Central')
def utc_to_central(s):
dt = datetime.strptime(s, '%Y%m%dT%H%M%SZ')
dt = utc.localize(dt)
return dt.astimezone(central)
def today():
dt = datetime.utcnow()
dt = utc.localize(dt)
dt = dt.astimezone(central)
return datetime.strftime(dt, '%Y%m%d')
def time_to_string(t):
s = str(1 + ((t.hour - 1) % 12))
if t.minute:
s += ':%02d' % t.minute
if t.hour > 11:
s += 'pm'
else:
s += 'am'
return s
Responding to a text
# main.py
from flask import Flask
app = Flask(__name__)
app.config['DEBUG'] = True
from util import today
from models import Event
from google.appengine.ext import ndb
import twilio.twiml
@app.route('/message', methods=['GET', 'POST'])
def reply():
query = Event.query(Event.date == today())
messages = []
for event in query:
messages.append('%s %s (%s)' %
(event.start, event.summary, event.location))
response = twilio.twiml.Response()
if len(messages) == 0:
response.message('No events today')
else:
response.message(' | '.join(messages))
return str(response)
- Purchase a Twilio phone number
- Set the SMS request url to http://your.site/message
Park Life
By David Radcliffe
Park Life
- 1,070