{"id":196,"date":"2011-01-01T11:49:55","date_gmt":"2011-01-01T16:49:55","guid":{"rendered":"http:\/\/blogs.cae.tntech.edu\/mwr\/?p=196"},"modified":"2024-10-27T14:26:19","modified_gmt":"2024-10-27T14:26:19","slug":"work-in-progress-tweetable-office-door-sign","status":"publish","type":"post","link":"https:\/\/sites.tntech.edu\/renfro\/2011\/01\/01\/work-in-progress-tweetable-office-door-sign\/","title":{"rendered":"Work in Progress: Tweetable Office Door Sign"},"content":{"rendered":"<p>A sizable amount of my work week is spent outside of my office, and is difficult to schedule ahead of time:<\/p>\n<ul>\n<li>Material testing jobs show up with little notice.<\/li>\n<li>Students or faculty need help fixing a coding, instrumentation, or other problem, and it&#8217;s easiest to fix those on-site rather than in my office.<\/li>\n<li>etc.<\/li>\n<\/ul>\n<p>I&#8217;ve got a spot on my door for a 3&#215;5 index card where I can post my known schedule (classes, regular meetings, that sort of thing), but I&#8217;ve always had to keep a stack of Post-It notes on hand for the other places I often go. The problem with the Post-It method is that I&#8217;ll often get called off to another location before I can get back to my office, and the notes quickly become inaccurate. And the notes can easily get misplaced or out of order, making them less useful.<\/p>\n<p>And I liked the concept of the <a href=\"http:\/\/www.panic.com\/blog\/2010\/03\/the-panic-status-board\/\">Panic Status Board<\/a>, too.<\/p>\n<p>So what I&#8217;m working on instead is a door sign I can update over the network from my smartphone, my home or office PC, someone else&#8217;s computer, etc. My office door already has a 12 inch square window in it, so any display I mount there can be protected, at least when the door is closed. There are several ways I could do this with varying tradeoffs:<\/p>\n<ul>\n<li><a href=\"http:\/\/www.ladyada.net\/make\/ybox2\/\">YBox2<\/a> plus LCD TV and Twitter feed. Pros: would work out of the box for $150 in hardware costs and a bit of assembly and soldering. Cons: without modifying the Twitter widget code, I&#8217;d have to worry about the risk of someone else switching my door sign to another Twitter user, or else put the YBox2 on an isolated and firewalled network segment. And I&#8217;d have to either learn soldering or beg someone else to put it together for me.<\/li>\n<li>Two XBee modules, one USB adapter, one compatible character LCD screen, and an always-on computer (probably my Mac Mini, since my main office PC is an often-mobile laptop). Pros: all the customization I&#8217;d ever want. Cons: all the customization I&#8217;d never want to implement. And more soldering.<\/li>\n<li>Arduino, Ethernet shield, and firmware to parse an RSS or Twitter feed. Pros: probably easier to customize the firmware than the YBox2. Cons: $100 or more in hardware.<\/li>\n<li><a href=\"http:\/\/www.seeedstudio.com\/depot\/preorder-twatch-v2-with-lcd-assembled-p-510.html\">#twatch<\/a> as an LCD Smartie display. Pros: super-cheap at $40 assembled. Cons: needing LCD Smartie to run on OS X, plus needing an extra network interface for the Mini.<\/li>\n<li>Chumby or other Internet-connected display device. Pros: cheap, especially the <a href=\"http:\/\/www.bestbuy.com\/site\/Insignia%26%23153%3B+-+Infocast+3.5%22+Internet+Media+Display\/1152881.p?id=1218226456157&amp;skuId=1152881\">$50 Insignia-branded one<\/a> at Best Buy. Wifi built in. Cons: customization limited to whatever widgets people have already posted, or to my ability to code my own Flash widgets.<\/li>\n<\/ul>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-198\" src=\"http:\/\/sites.tntech.edu\/renfro\/wp-content\/uploads\/sites\/111\/2011\/01\/1152881_rb.jpg\" alt=\"\" width=\"220\" height=\"209\" \/><br \/>\nI ended up buying an Insignia Chumby because for $50, even if I just made it into a smarter alarm clock with MP3 and FM radio playback, it&#8217;d be an improvement over my current home clock. But I think it&#8217;ll end up working out well for my door sign. The setup details follow after the jump:<br \/>\n<!--more--><\/p>\n<ol>\n<li>Dedicated Twitter account for the door sign. I have an unused personal Twitter account, too, but I want to keep the door sign content separated from anything irrelevant I might post on my personal feed.<\/li>\n<li>Whatever Twitter application I want. For this particular application, I&#8217;ll keep a browser logged in to my door sign Twitter account, and point it to a simple page that can fill out a default status on the Twitter website. That way, all I have to do is click one link, optionally edit the status, and hit the Tweet button on the site.<\/li>\n<li><a href=\"http:\/\/www.chumby.com\/guide\/widget\/12%20Hour%20Flip%20Clock%20-%20Black\">12-Hour Flip Clock (Black) app<\/a> with a 15-second play time.<\/li>\n<li><a href=\"http:\/\/www.chumby.com\/guide\/widget\/Chumby%20RSS%20Reader\">Chumby RSS Reader app<\/a> with a 45-second play time. By default, this will let you tap forward and back through a given RSS feed. I could have used the Twitter app, but I really want to keep my sign&#8217;s Twitter ID as private as possible. I don&#8217;t want to worry about followers, protecting the tweets, etc. If I can get an RSS feed of the tweets, I stand a chance of sanitizing the content so it shows only what I want, in whatever format I want, and nothing more.<\/li>\n<li>Short Python script and cron job that filters my door sign feed, and saves the output somewhere accessible to the RSS Reader app.<\/li>\n<li>Modifying the web server hosting the RSS feed to ensure that the feed doesn&#8217;t get cached for more than 1 minute.<\/li>\n<\/ol>\n<h1>Page of Twitter Status Bookmarks<\/h1>\n<p>The basic page looks like this on WebOS:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-203\" src=\"http:\/\/sites.tntech.edu\/renfro\/wp-content\/uploads\/sites\/111\/2011\/01\/browser_2011-01-01_111801.png\" alt=\"\" width=\"320\" height=\"480\" srcset=\"https:\/\/sites.tntech.edu\/renfro\/wp-content\/uploads\/sites\/111\/2011\/01\/browser_2011-01-01_111801.png 320w, https:\/\/sites.tntech.edu\/renfro\/wp-content\/uploads\/sites\/111\/2011\/01\/browser_2011-01-01_111801-200x300.png 200w\" sizes=\"auto, (max-width: 320px) 100vw, 320px\" \/><\/p>\n<p>The contents of my page are nothing more than a series of links to twitter.com:<\/p>\n<pre>\n<pre>&lt;p&gt;Clement Hall:\n    &lt;a href=\"<a href=\"http:\/\/twitter.com\/?status=In%20Clement%20101\">http:\/\/twitter.com\/?status=In Clement 101<\/a>\"&gt;101&lt;\/a&gt; |\n    &lt;a href=\"<a href=\"http:\/\/twitter.com\/?status=In%20Clement%20113\">http:\/\/twitter.com\/?status=In Clement 113<\/a>\"&gt;113&lt;\/a&gt; |\n    ...\n&lt;\/p&gt;<\/pre>\n<p>Clicking a link (for example, Clement Hall 113) takes me to the Twitter site and has the status text ready to edit or post as-is:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-204\" src=\"http:\/\/sites.tntech.edu\/renfro\/wp-content\/uploads\/sites\/111\/2011\/01\/browser_2011-01-01_111849.png\" alt=\"\" width=\"320\" height=\"480\" srcset=\"https:\/\/sites.tntech.edu\/renfro\/wp-content\/uploads\/sites\/111\/2011\/01\/browser_2011-01-01_111849.png 320w, https:\/\/sites.tntech.edu\/renfro\/wp-content\/uploads\/sites\/111\/2011\/01\/browser_2011-01-01_111849-200x300.png 200w\" sizes=\"auto, (max-width: 320px) 100vw, 320px\" \/><\/p>\n<h1>Python script<\/h1>\n<pre>#!\/usr\/bin\/python\n\n# Grabs most recent tweet from RSS and reformats it for Chumby RSS\n# Reader app\n\n# Final Chumby display format:\n#\n# - feed_title\n# - item_title\n# - item_description (with Twitter ID removed, and appending timestamp\n#   in local time)\n\n# Credits:\n# http:\/\/stackoverflow.com\/questions\/1766823\/how-can-i-generate-rss-with-arbitrary-tags-and-enclosures\n\nimport feedparser, PyRSS2Gen, string\nfrom datetime import datetime, timedelta\nfrom pytz import timezone\nimport pytz\n\ntwitter_id = \"REPLACEME\"\nfeed_title = \"Mike Renfro &lt;renfro@tntech.edu&gt;\"\nitem_title = \"Where's Mike?\"\ntz = timezone('US\/Central')\ntimestamp_format = ' (%A, %B %-d, %-I:%M %p)'\n\ntry:\n    parsed_feed = feedparser.parse(\"http:\/\/twitter.com\/statuses\/user_timeline\/%s.rss\" % (twitter_id))\n    items = [\n        PyRSS2Gen.RSSItem(\n        title = item_title,\n        link = x.link,\n        description = string.replace(x.summary,\"%s: \" % (twitter_id),\"\")+\\\n        datetime(x.modified_parsed[0],\n                 x.modified_parsed[1],\n                 x.modified_parsed[2],\n                 x.modified_parsed[3],\n                 x.modified_parsed[4],\n                 x.modified_parsed[5],\n                 tzinfo=pytz.utc).astimezone(tz).strftime(timestamp_format),\n        guid = x.link)\n        for x in parsed_feed.entries[:1] ]\n\nexcept:\n    # Occasionally, the feed will fail, and be fine the next time I\n    # check it. Since this isn't critical information, I'll just not\n    # write any output at all.\n    pass\n\nelse:\n\n    try:\n        rss = PyRSS2Gen.RSS2(\n            title = feed_title,\n            link = parsed_feed.feed.link,\n            description = parsed_feed.feed.description,\n            items = items[:1]\n            )\n\n    except:\n        # Occasionally, the feed will fail, and be fine the next time\n        # I check it. Since this isn't critical information, I'll just\n        # not write any output at all.\n        pass\n\n    else:\n        f = open('OUTFILE.rss','w')\n        f.write(rss.to_xml())\n        f.close()\n<\/pre>\n<p>And the cron job that runs every minute to update the sign is just<\/p>\n<pre>(cd \/FOLDER &amp;&amp; .\/SCRIPT.py )\n<\/pre>\n<h1>Web Server Modifications<\/h1>\n<p>I needed to enable and configure the Apache module <code>mod_expires<\/code>. Since my web server is Debian, all that required was running <code>a2enmod expires<\/code>, adding <code>ExpiresActive On<\/code> and <code>ExpiresByType application\/rss+xml \"modification plus 1 minute\"<\/code> to the Apache virtual host entry, and finally reloading the Apache process.<\/p>\n<h1>Results<\/h1>\n<p>Here&#8217;s a resulting image from a virtual Chumby. The script removed my Twitter ID, and also added the date and time I posted the update. The original Twitter feed is untouched, and I can even make another page  with the virtual Chumby Flash object embedded if someone wanted to see  my status from somewhere else.<\/p>\n<p style=\"text-align: center\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter\" src=\"http:\/\/sites.tntech.edu\/renfro\/wp-content\/uploads\/sites\/111\/2010\/12\/door-sign-rss.png\" alt=\"\" width=\"324\" height=\"244\" \/><\/p>\n<p>That&#8217;s it. <del datetime=\"2011-01-13T16:55:12+00:00\">All that&#8217;s left is to get the Chumby on the campus Wireless network, physically mount it in my office door window, and run power to it.<\/del><\/p>\n","protected":false},"excerpt":{"rendered":"<p>A sizable amount of my work week is spent outside of my office, and is difficult to schedule ahead of time: Material testing jobs show up with little notice. Students or faculty need help fixing a coding, instrumentation, or other problem, and it&#8217;s easiest to fix those on-site rather than in my office. etc. I&#8217;ve &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/sites.tntech.edu\/renfro\/2011\/01\/01\/work-in-progress-tweetable-office-door-sign\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Work in Progress: Tweetable Office Door Sign&#8221;<\/span><\/a><\/p>\n","protected":false},"author":87,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[13,17],"tags":[],"class_list":["post-196","post","type-post","status-publish","format-standard","hentry","category-organization","category-python","entry"],"_links":{"self":[{"href":"https:\/\/sites.tntech.edu\/renfro\/wp-json\/wp\/v2\/posts\/196","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/sites.tntech.edu\/renfro\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sites.tntech.edu\/renfro\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sites.tntech.edu\/renfro\/wp-json\/wp\/v2\/users\/87"}],"replies":[{"embeddable":true,"href":"https:\/\/sites.tntech.edu\/renfro\/wp-json\/wp\/v2\/comments?post=196"}],"version-history":[{"count":1,"href":"https:\/\/sites.tntech.edu\/renfro\/wp-json\/wp\/v2\/posts\/196\/revisions"}],"predecessor-version":[{"id":446,"href":"https:\/\/sites.tntech.edu\/renfro\/wp-json\/wp\/v2\/posts\/196\/revisions\/446"}],"wp:attachment":[{"href":"https:\/\/sites.tntech.edu\/renfro\/wp-json\/wp\/v2\/media?parent=196"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sites.tntech.edu\/renfro\/wp-json\/wp\/v2\/categories?post=196"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sites.tntech.edu\/renfro\/wp-json\/wp\/v2\/tags?post=196"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}