From b53304ea382fbb09413f992d60b28711f347039f Mon Sep 17 00:00:00 2001 From: Edward Saxton Date: Tue, 25 Jun 2013 11:48:14 +0000 Subject: [PATCH 1/3] Pull generic code into its own lib Break appart Weather and Stocks now JSON is seperate --- Python_Examples/PiLiteLib.py | 63 +++++++++++++++++++ .../{PiLiteJson.py => PiLiteStock.py} | 33 +--------- Python_Examples/PiLiteTwitter.py | 34 +--------- Python_Examples/PiLiteWeather.py | 30 +++++++++ Python_Examples/PiLiteWorldTime.py | 17 +---- 5 files changed, 98 insertions(+), 79 deletions(-) create mode 100644 Python_Examples/PiLiteLib.py rename Python_Examples/{PiLiteJson.py => PiLiteStock.py} (50%) create mode 100755 Python_Examples/PiLiteWeather.py diff --git a/Python_Examples/PiLiteLib.py b/Python_Examples/PiLiteLib.py new file mode 100644 index 0000000..3b0d363 --- /dev/null +++ b/Python_Examples/PiLiteLib.py @@ -0,0 +1,63 @@ +from collections import deque +from time import sleep + +import requests +import serial + + +class PiLiteBoard(object): + def __init__(self): + self.ser = serial.Serial("/dev/ttyAMA0", baudrate=9600, timeout=3.0) + self.ser.write("$$$SPEED50\r") + + def write(self, text): + text = text.encode('utf-8') + while text: + self.ser.write(text[:14]) + text = text[14:] + sleep(3) + + +def poll_for_updates(source, sink, interval=60, repeat=True): + oldstatus = None + while True: + try: + status = source.message() + if repeat or status != oldstatus: + print(status) + oldstatus = status + sink.write(status) + except (KeyboardInterrupt, SystemExit): + raise + except Exception as e: + print("Error:" + str(e)) + sink.write("...oops...error...") + sink.write(str(e)) + sleep(interval) + + +class JSONPoll(object): + def __init__(self, url, message_format, params=None): + self.url = url + self.message_format = message_format + self.params = params or {} + + def message(self): + data = requests.get(self.url, params=self.params).json() + return self.message_format.format(**self.mung_data(data)) + + def mung_data(self, data): + return data + + +class CyclingSources(object): + def __init__(self, *sources): + self.sources = deque(sources) + + def message(self): + message = self.sources[0].message() + self.sources.rotate(-1) + return message + + def __len__(self): + return len(self.sources) diff --git a/Python_Examples/PiLiteJson.py b/Python_Examples/PiLiteStock.py similarity index 50% rename from Python_Examples/PiLiteJson.py rename to Python_Examples/PiLiteStock.py index 66a9561..8a7311e 100755 --- a/Python_Examples/PiLiteJson.py +++ b/Python_Examples/PiLiteStock.py @@ -1,36 +1,7 @@ #!/usr/bin/env python import urllib -import requests - -from PiLiteTwitter import PiLiteBoard, poll_for_updates - - -class JSONPoll(object): - def __init__(self, url, message_format, params=None): - self.url = url - self.message_format = message_format - self.params = params or {} - - def message(self): - data = requests.get(self.url, params=self.params).json() - return self.message_format.format(**self.mung_data(data)) - - def mung_data(self, data): - return data - - -class WeatherPoll(JSONPoll): - def __init__(self, location, message_format=""): - default_format = "{name}: {weather[0][description]}, {main[temp_c]:.0f}C" - base_url = "http://api.openweathermap.org/data/2.5/weather?q=%s" - super(WeatherPoll, self).__init__(base_url%location, - message_format or default_format) - - def mung_data(self,data): - """ Convert local temperature from K to C""" - data['main']['temp_c'] = data['main']['temp']-273.15 - return super(WeatherPoll, self).mung_data(data) +from PiLiteLib import PiLiteBoard, poll_for_updates, JSONPoll class StockPoll(JSONPoll): @@ -48,12 +19,12 @@ def __init__(self, stock, message_format=""): def mung_data(self, data): """ Drill down to the result to make message_format more readable""" + print data return super(StockPoll, self).mung_data(data['query']['results']['quote']) def main(): - #source = WeatherPoll("London,uk") source = StockPoll("MSFT") sink = PiLiteBoard() print("ready") diff --git a/Python_Examples/PiLiteTwitter.py b/Python_Examples/PiLiteTwitter.py index ad18b50..0adecd2 100755 --- a/Python_Examples/PiLiteTwitter.py +++ b/Python_Examples/PiLiteTwitter.py @@ -33,23 +33,11 @@ import ConfigParser import os -from time import sleep import twitter -import serial -class PiLiteBoard(object): - def __init__(self): - self.ser = serial.Serial("/dev/ttyAMA0", baudrate=9600, timeout=3.0) - self.ser.write("$$$SPEED50\r") - - def write(self, text): - text = text.encode('utf-8') - while text: - self.ser.write(text[:14]) - text = text[14:] - sleep(3) +from PiLiteLib import PiLiteBoard, poll_for_updates class TwitterTimeline(object): @@ -67,30 +55,12 @@ def message(self): return "@%s::%s..."%(status.GetUser().GetScreenName(), status.GetText()) -def poll_for_updates(source, sink, interval=60): - oldstatus = None - while True: - try: - status = source.message() - if status != oldstatus: - print(status) - oldstatus = status - sink.write(status) - except (KeyboardInterrupt, SystemExit): - raise - except Exception as e: - print("Error:" + str(e)) - sink.write("...oops...error...") - sink.write(str(e)) - sleep(interval) - - def main(): source = TwitterTimeline() sink = PiLiteBoard() print("ready") sink.write("ready ") - poll_for_updates(source, sink) + poll_for_updates(source, sink, repeat=False) if __name__ == "__main__": diff --git a/Python_Examples/PiLiteWeather.py b/Python_Examples/PiLiteWeather.py new file mode 100755 index 0000000..1c18c02 --- /dev/null +++ b/Python_Examples/PiLiteWeather.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python +import urllib + +from PiLiteLib import PiLiteBoard, poll_for_updates, JSONPoll + + +class WeatherPoll(JSONPoll): + def __init__(self, location, message_format=""): + default_format = "{name}: {weather[0][description]}, {main[temp_c]:.0f}C" + base_url = "http://api.openweathermap.org/data/2.5/weather?q=%s" + super(WeatherPoll, self).__init__(base_url%location, + message_format or default_format) + + def mung_data(self,data): + """ Convert local temperature from K to C""" + data['main']['temp_c'] = data['main']['temp']-273.15 + return super(WeatherPoll, self).mung_data(data) + + + +def main(): + source = WeatherPoll("London,uk") + sink = PiLiteBoard() + print("ready") + sink.write("ready ") + poll_for_updates(source, sink) + + +if __name__ == "__main__": + main() diff --git a/Python_Examples/PiLiteWorldTime.py b/Python_Examples/PiLiteWorldTime.py index 36f31ac..c7fa62b 100755 --- a/Python_Examples/PiLiteWorldTime.py +++ b/Python_Examples/PiLiteWorldTime.py @@ -1,9 +1,7 @@ #!/usr/bin/env python -from collections import deque - import arrow -from PiLiteTwitter import PiLiteBoard, poll_for_updates +from PiLiteLib import PiLiteBoard, poll_for_updates, CyclingSources class WorldTime(object): @@ -15,19 +13,6 @@ def message(self): now = arrow.utcnow().to(self.timezone) return "{} : {}".format(self.label, now.format("HH:mm:ss")) - -class CyclingSources(object): - def __init__(self, *sources): - self.sources = deque(sources) - - def message(self): - message = self.sources[0].message() - self.sources.rotate(-1) - return message - - def __len__(self): - return len(self.sources) - def main(): source = CyclingSources(WorldTime("London", "Europe/London"), From cf61a62e1b5e67a3e9553afb93e18092a5cfd725 Mon Sep 17 00:00:00 2001 From: Edward Saxton Date: Tue, 25 Jun 2013 11:48:52 +0000 Subject: [PATCH 2/3] Fix url encoding for yahoo stock api --- Python_Examples/PiLiteStock.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Python_Examples/PiLiteStock.py b/Python_Examples/PiLiteStock.py index 8a7311e..6d4d7d1 100755 --- a/Python_Examples/PiLiteStock.py +++ b/Python_Examples/PiLiteStock.py @@ -9,17 +9,16 @@ def __init__(self, stock, message_format=""): """ Encoding a space in the url a + breaks YQL, so requests params handling can't be used """ - default_format = "{symbol} {DaysLow},{DaysHigh}" + default_format = "{symbol} {Bid},{PercentChange}" base_url = "http://query.yahooapis.com/v1/public/yql" - querystring = "select * from yahoo.finance.quotes where symbol='%s'" + querystring = "from yahoo.finance.quotes where symbol='%s'" fmt = "format=json" - env = "env="+urllib.quote("store://datatables.org/alltableswithkeys") - url = "%s?q=%s&%s&%s"%(base_url, urllib.quote(querystring%stock), fmt, env) + env = "env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys" + url = "%s?q=select%%20*%%20%s&%s&%s"%(base_url, urllib.quote(querystring%stock), fmt, env) super(StockPoll, self).__init__(url, message_format or default_format) def mung_data(self, data): """ Drill down to the result to make message_format more readable""" - print data return super(StockPoll, self).mung_data(data['query']['results']['quote']) From c100133bedbcfe52c825d35303f6192a0d089fc0 Mon Sep 17 00:00:00 2001 From: Edward Saxton Date: Tue, 25 Jun 2013 11:49:23 +0000 Subject: [PATCH 3/3] Provide more info on Xively datastreams --- Python_Examples/PiLiteXively.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Python_Examples/PiLiteXively.py b/Python_Examples/PiLiteXively.py index 35084c5..7f28c1d 100755 --- a/Python_Examples/PiLiteXively.py +++ b/Python_Examples/PiLiteXively.py @@ -17,8 +17,8 @@ def __init__(self, feed): def message(self): feed = self.api.feeds.get(self.feedid) - value = feed.datastreams[0].current_value - return "%s"%value + stream = feed.datastreams[0] + return "%s %s %s %s"%(feed.title, stream.id, stream.current_value, stream.unit.label) def main():