<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>API Archives | DMC, Inc.</title>
	<atom:link href="https://static.dmcinfo.com/blog/tag/api/feed/index.xml" rel="self" type="application/rss+xml" />
	<link></link>
	<description></description>
	<lastBuildDate>Fri, 21 Aug 2026 15:04:01 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.1.2</generator>

<image>
	<url>https://static.dmcinfo.com/wp-content/uploads/2025/04/site-icon-150x150.png</url>
	<title>API Archives | DMC, Inc.</title>
	<link></link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Creating an Augmented Reality (AR) Demo with the Vuforia Studio Pilot Program</title>
		<link>https://static.dmcinfo.com/blog/25084/creating-an-augmented-reality-ar-demo-with-the-vuforia-studio-pilot-program/</link>
		
		<dc:creator><![CDATA[Cecilia Tetlow]]></dc:creator>
		<pubDate>Thu, 06 Oct 2016 16:15:55 +0000</pubDate>
				<category><![CDATA[Application Development]]></category>
		<category><![CDATA[Embedded Development & Programming]]></category>
		<category><![CDATA[User Interface Design]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[IoT]]></category>
		<category><![CDATA[SDK]]></category>
		<guid isPermaLink="false">https://static.dmcinfo.com/blog/25084/creating-an-augmented-reality-ar-demo-with-the-vuforia-studio-pilot-program/</guid>

					<description><![CDATA[<p>Augmented Reality (AR) has been booming the past couple of months, especially with the deployment of Pokémon Go. If you&#8217;re not familiar with it, Pokémon Go is a mobile app that encourages its users to walk around the real world in order to capture virtual Pokémon characters. Aside from making a very addicting mobile phone [&#8230;]</p>
<p>The post <a href="https://static.dmcinfo.com/blog/25084/creating-an-augmented-reality-ar-demo-with-the-vuforia-studio-pilot-program/">Creating an Augmented Reality (AR) Demo with the Vuforia Studio Pilot Program</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Augmented Reality (AR) has been booming the past couple of months, especially with the deployment of Pokémon Go. If you&#8217;re not familiar with it, Pokémon Go is a mobile app that encourages its users to walk around the real world in order to capture virtual Pokémon characters.</p>



<p class="wp-block-paragraph">Aside from making a very addicting mobile phone application, AR is now being considered in industrial settings. It can be used to diagnose and&nbsp;troubleshoot machinery, or&nbsp;provide visual instructions for assembly or disassembly. For example, this <a href="https://www.youtube.com/watch?v=mru4tRsjqpk&amp;feature=youtu.be" target="_blank">video</a>&nbsp;shows an AR program walking the user through the steps of changing a circular saw blade. This particular program was created with the Vuforia Studio Pilot Program.</p>



<h2 id="h-vuforia-studio-pilot-program" class="wp-block-heading">Vuforia Studio Pilot Program</h2>



<p class="wp-block-paragraph">&nbsp;</p>



<p class="wp-block-paragraph">The Vuforia Studio Pilot Program integrates 3 distinct platforms: ThingWorx, Vuforia, and PTC Creo Illustrate. <a href="http://www.ptc.com/internet-of-things/technology-platform-thingworx" target="_blank">ThingWorx</a> is crucial for transmitting data between devices, such as sensor data collected from a Raspberry Pi to&nbsp;a phone.&nbsp;PTC Creo Illustrate&nbsp;is a technical illustration software that allows you to create 3D sequences and animations with CAD data. <a href="https://developer.vuforia.com/" target="_blank">Vuforia</a> can then import&nbsp;data from ThingWorx and integrate it with the 3D models and animations from PTC Creo Illustrate to create an&nbsp;AR environment. With these three platforms, the Vuforia Studio Pilot Program is capable of creating some really cool AR experiences.</p>



<p class="wp-block-paragraph">I created an AR experience for the 2016 AWC BestFest with the Vuforia Studio Pilot Program. If you&#8217;re interested in using the techniques mentioned in this post to create your very own AR experience, sign up for the <a href="https://www.vuforia.com/studio" type="link" id="https://www.vuforia.com/studio">Vuforia Studio Pilot Program</a>. You&#8217;ll then get a service URL that contains your ThingWorx and Vuforia instance.</p>



<h2 id="h-2016-awc-bestfest-beer-tank-demo" class="wp-block-heading">2016 AWC BestFest Beer Tank Demo</h2>



<p class="wp-block-paragraph">&nbsp;</p>



<p class="wp-block-paragraph">The <a href="http://www.bestfest.us/" target="_blank">2016 AWC BestFest</a>&nbsp;is a technology tradeshow held at Saint Arnold&#8217;s brewery in Houston, Texas. The festival is an opportunity for technology partners to mingle, show off new technologies, and drink beer. Another DMC employee gave a seminar on &#8220;Smart Manufacturing&#8221; and how IoT platforms can improve the industrial process. We decided some AR demos with IoT platforms would help illustrate this point. Being at Saint Arnold&#8217;s Brewery, I though it was fitting to have a demo centered around a beer tank.</p>



<p class="wp-block-paragraph"><iframe allowfullscreen="" frameborder="0" height="360" src="https://www.youtube.com/embed/2VB_N0NqFEg" width="640"></iframe></p>



<p class="wp-block-paragraph">For the demo, the user scans a specific &#8220;ThingMark&#8221; with their smartphone. These ThingMarks are essentially QR codes that are tied to unique augmented reality experiences. When you sign up for the pilot program, you get 100 different ThingMarks for your projects.&nbsp;</p>



<p class="wp-block-paragraph"><p style="text-align: center;"><img decoding="async" alt="ThingMark for BestFest" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/BestFest_1.png"></p></p>



<p class="wp-block-paragraph">Upon scanning the ThingMark,&nbsp;a 3D CAD model of a beer tank appears on the screen&nbsp;alongside&nbsp;with temperature and tank level values. The temperature and tank level values were simulated through a python script on a Raspberry Pi. Additionally, I created a step-by-step visual sequence that showed the user how to open the lid at the top of the tank.&nbsp;</p>



<p class="wp-block-paragraph"><p style="text-align: center;"><img decoding="async" alt="View from smartphone of 2016 BestFest Demo" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Beer-Tank-Augmented-Reality-Vuforia-Pilot.png">&nbsp; &nbsp; &nbsp;&nbsp; &nbsp;<img decoding="async" alt="Snapshot of sequence from 2016 BestFest Demo" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Augmented-Reality-Sequence-Vuforia.png">&nbsp; &nbsp; &nbsp;</p></p>



<p class="wp-block-paragraph">The following sections give a brief overview of how I accomplished it.&nbsp; &nbsp;</p>



<p class="wp-block-paragraph"><em>Setting Up&nbsp;ThingWorks&nbsp;</em></p>



<p class="wp-block-paragraph">ThingWorx Foundation is an Internet of Things (IoT) platform that strives to create a &#8220;smart, and connected world&#8221;. What does this mean exactly? In this smart world, any and all electronic devices would be able to communicate with each other and execute services. For example, your printer would order its own ink cartridges after detecting low ink levels instead of relying on you. Or, your alarm would adjust when it woke you up depending on whether the train was early or late (look at this DMC <a href="https://static.dmcinfo.com/latest-thinking/blog/id/8568/categoryid/134/cta-bus-tracking-with-the-raspberry-pi" target="_blank">blog</a> for a similar project on how to track CTA Buses with a Raspberry Pi). Learn more about how DMC can help you with <a href="https://static.dmcinfo.com/services/embedded-development-and-embedded-programming/iot-solutions/" data-type="link" data-id="https://static.dmcinfo.com/services/embedded-development-and-embedded-programming/iot-solutions/">your IoT projects</a>.  </p>



<p class="wp-block-paragraph"><em>Creating ThingShapes, ThingTemplates, and Things</em></p>



<p class="wp-block-paragraph">ThingWorx is an object-oriented&nbsp;platform centered&nbsp;around &#8220;Things&#8221;. There are&nbsp;Things,&nbsp;Thing Templates, and&nbsp;Thing Shapes. Thing Shapes are the lowest level, and this is where you define properties, services, events, and subscriptions. So I created two Thing Shapes: TankTempShape, and TankFillShape. Here is where I first defined the temperature, fill level, name, and other properties I wanted to keep track of.&nbsp;I&nbsp;then created a Thing Template called TankTemplate that inherits from my two Thing Shapes. Finally, I created TankThing that inherits from my TankTemplate. The advantage to this object-oriented structure is that I do not have to redefine properties for each Thing I want to set up. If I had multiple beer tanks I wanted to track, then I could easily create several TankThing&#8217;s and each one would inherit from&nbsp;TankTemplate and already have the proper configurations. Alternatively, you could define all your properties and configurations within&nbsp;your Thing and it would work fine, but you would not be able to easily scale up your model.&nbsp;Once I created my TankThing, I had to ensure that I could receive data from my Raspberry Pi by setting up an application key.</p>



<p class="wp-block-paragraph"><em>Creating&nbsp;an Application Key</em></p>



<p class="wp-block-paragraph">Each time you access your ThingWorx instance, you must login with your user credentials. So when you make an HTTP request&nbsp;with the Raspberry Pi, you&#8217;ll&nbsp;need to send along the username and password&nbsp;before you can alter the ThingWorx data. Alternatively, you can create an application key within ThingWorx for the specified user. Now when we make the HTTP request&nbsp;you&nbsp;can pass along the application key ID instead. Under&nbsp;the home tab, under security, there is a section for application keys. If there isn&#8217;t one already created, create a new one for the user you want to use (I used Administrator). Make sure your user has the proper read and write access. When you save it, it should generate an application key ID. Save this ID, you will need it in the next section.</p>



<h2 id="h-raspberry-pi-data-simulation" class="wp-block-heading">Raspberry Pi Data Simulation</h2>



<p class="wp-block-paragraph">&nbsp;</p>



<p class="wp-block-paragraph">While I chose to simulate data within a python script, you can collect data from a sensor and export that to ThingWorx instead. In order to do that, you&#8217;ll need to utilize the GPIO library. You can use this <a href="https://learn.sparkfun.com/tutorials/raspberry-gpio/python-rpigpio-api" target="_blank">reference</a> to set up your inputs to collect sensor data. While I&#8217;m not going to go over my simulation code (wouldn&#8217;t really help you unless you wanted to run through the exact same numbers as me), I&#8217;m going to show you how to set up the HTTP request.</p>



<p class="wp-block-paragraph"><i>Making an HTTP Request to Edit ThingWorx</i></p>



<p class="wp-block-paragraph">In order to do this, you will need to import the JSON and Requests library. The Requests library is an awesome tool that makes HTTP requests really simple. Everything you need can be condensed into one line of code.</p>



<p class="wp-block-paragraph"><p style="text-align: center;"><img decoding="async" alt="How to set up JSON and Requests libraries." src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Raspberry_Pi_JSON_Requests_libraries.png"></p></p>



<p class="wp-block-paragraph">If you don&#8217;t have the Requests library already installed, enter the following lines&nbsp;into the&nbsp;terminal&nbsp;to get them.</p>



<ol class="wp-block-list">
<li>&nbsp;sudo git clone git://github.com/kennethreitz/requests.git &nbsp;</li>



<li>&nbsp;cd requests (i.e. change directory into the folder that git has just added)</li>



<li>&nbsp;sudo python setup.py install</li>
</ol>



<p class="wp-block-paragraph">Now you&#8217;re ready for the&nbsp;HTTP request. The&nbsp;following&nbsp;lines of code only work for my specific ThingWorx and Vuforia instance.&nbsp;You&#8217;ll&nbsp;need to replace the URL&nbsp;with your service URL, replace the blacked out portion with the application key ID from your ThingWorx, and replace TankThing with the name of your Thing. That will ensure that the Raspberry Pi is sending the data to the correct location.</p>



<p class="wp-block-paragraph">Lastly, you&#8217;ll need to edit the payload line with your own custom variables. The blue text corresponds to the properties within ThingWorx,&nbsp;and the black text corresponds to the variables within the python script.</p>



<p class="wp-block-paragraph"><p style="text-align: center;"><img decoding="async" alt="Variables used in http request to ThingWorx." src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Service_URL_ThingWorx_Application_Key_AR.png"></p></p>



<p class="wp-block-paragraph"><p style="text-align: center;"><img decoding="async" alt="http request to edit data in ThingWorx instance." src="https://static.dmcinfo.com/wp-content/uploads/2025/05/HTTP_Request_ThingWorx.png"></p></p>



<p class="wp-block-paragraph"><p style="text-align: center;">&nbsp;</p></p>



<p class="wp-block-paragraph">&nbsp;</p>



<p class="wp-block-paragraph">&nbsp;</p>



<p class="wp-block-paragraph">Afterwards, save your python script and execute it from the terminal. You can test the script by going into ThingWorx and checking&nbsp;your Thing&#8217;s properties. Hit the blue refresh button next to Values to see the values change. If it&#8217;s not updating, check to make sure the URL, Thing name, application key, and payload terms are correctly typed. Also check that your python script is properly collecting/simulating values.</p>



<h2 id="h-ptc-creo-illustrate" class="wp-block-heading">PTC Creo Illustrate</h2>



<p class="wp-block-paragraph">&nbsp;</p>



<p class="wp-block-paragraph"><em>Import an Existing CAD Model</em></p>



<p class="wp-block-paragraph">PTC Creo Illustrate is a great program for creating animations and visuals, however, you can&#8217;t create CAD models. You can use other programs such as PTC Creo Parametric, PTC Creo Elements, SolidWorks, or AutoCAD to create your own model. Alternatively, you can&nbsp;download a file from GrabCAD or other free sites. Once you&#8217;re ready to import, go to File -&gt; Import and then select your CAD file. When you click Open you should get a&nbsp;window similar to the one below.</p>



<p class="wp-block-paragraph"><p style="text-align: center;"><img decoding="async" alt="PTC Creo Illustrate Intro" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/PTC_Creo_Illustrate_Beer_Tank_BestFest.png"></p></p>



<p class="wp-block-paragraph">Now you can make edits to your model like&nbsp;rotating&nbsp;or translating&nbsp;your device, creating&nbsp;sections, sequences, and animations. For my particular demo, I created a sequence &nbsp;that shows how to open the lid at the top of the beer tank.</p>



<p class="wp-block-paragraph"><em>Creating a Sequence</em></p>



<p class="wp-block-paragraph">You can create a sequence to showcase anything from assembly, disassembly, movement, or internal components.&nbsp;Once you have your figure imported, click on the &#8220;Sequence&#8221; tab at the top of the window. You&#8217;ll now see a slew of visual manipulation options.</p>



<p class="wp-block-paragraph"><p style="text-align: center;"><img decoding="async" alt="How to create a sequence in PTC Creo Illustrate" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Creating-Sequences-PTC-Creo-Illustrate-Intro.png"></p></p>



<p class="wp-block-paragraph">Click&nbsp;&#8220;Add Step&#8221; to begin the process. You can now add whatever motions you desire.&nbsp;There are several effects that you can add to individual pieces&nbsp;such as fly in/out, fade in/out, shake, pulse, unscrew, etc. Play around with them to determine what you want. You can add several effects to one step and PTC Creo will do its best to combine them all into one fluid motion. If you want them to be separated, make sure to put them in different steps. Continue to add steps, translations, and effects until you have the desired sequence. You can then go to &#8220;Preview Sequence&#8221; to view your entire sequence.</p>



<p class="wp-block-paragraph"><em>Publishing Your File</em></p>



<p class="wp-block-paragraph">Once you&#8217;re happy with your sequence, you&#8217;ll need to publish your program in order to get two files: .pvz file, and&nbsp;.pvi&nbsp;file. The .pvz file is your 3D model, whereas the .pvi file stores your animation information.&nbsp;</p>



<ol class="wp-block-list">
<li>Go to File -&gt; Publish.&nbsp;</li>



<li>Publish it as a new .pvz file.</li>



<li>Go to your new file and RENAME&nbsp;it as a zip file (do not send to a zip file, for some reason this does not seem to work).</li>



<li>Extract all files</li>
</ol>



<p class="wp-block-paragraph">After extraction, you should be able to see a .pvz file and a .pvi file in your new folder. These files will be imported into Vuforia Studio.</p>



<h2 id="h-vuforia-studio" class="wp-block-heading">Vuforia Studio</h2>



<p class="wp-block-paragraph">&nbsp;</p>



<p class="wp-block-paragraph">Here is where all the augmented reality magic happens. Here you&#8217;ll set up&nbsp;your 3D models, 2D and 3D widgets, ThingMark, and import ThingWorx data.&nbsp;&nbsp;&nbsp;</p>



<p class="wp-block-paragraph"><p style="text-align: center;"><img decoding="async" alt="Vuforia Studio view with 3D model and widgets" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Vuforia-Studio-Beer-Tank-3D-Model-View.png"></p></p>



<p class="wp-block-paragraph"><i>Importing Your 3D&nbsp;Model and Animation</i></p>



<p class="wp-block-paragraph">In order to use your 3D model and animations, you&#8217;ll need to import your files into Vuforia.</p>



<ol class="wp-block-list">
<li>On the left under Resources, click the blue plus sign.</li>



<li>Click Select File and find your .pvz file and click ADD.</li>



<li>Repeat&nbsp;for the .pvi file.</li>



<li>Close out of that window.&nbsp;</li>



<li>Drag a 3D Model into your environment.</li>



<li>To the right under the &#8220;Properties&#8221; column, go to&nbsp;&#8220;Resource&#8221; and select your .pvz file.</li>



<li>Under &#8220;Sequence URL&#8221;, select your .pvi file.</li>
</ol>



<p class="wp-block-paragraph"><em>Configuring a Button to Control Your Sequence</em></p>



<p class="wp-block-paragraph">Now we have a&nbsp;3D model and sequence imported into Vuforia, but nothing is currently telling it to run. To fix this, I configured&nbsp;toggle buttons that appear on the smartphone screen&nbsp;that execute&nbsp;play/rewind/forward actions.</p>



<ol class="wp-block-list">
<li>Select 2D view under Canvas.</li>



<li>Drag a Toggle Button onto any of the panels (your choice).</li>



<li>Under your Toggle Button properties, drag&nbsp;the blue cross icon next to &#8220;Click&#8221; all the way to the left&nbsp;to your 3D model icon under &#8220;Views&#8221;.</li>



<li>A new window will appear where you can select what action that button will have. Selecting&nbsp;&#8220;Play&#8221; will cause the next&nbsp;step in the sequence to play.</li>
</ol>



<p class="wp-block-paragraph">Add as many buttons as desired. As shown in the images of the 2016 BestFest demo,&nbsp;I had four distinct buttons: play, play all, rewind, and forward.&nbsp;You can also change what your buttons look&nbsp;like by changing &#8220;Image When Pressed&#8221; and &#8220;Image When Not Pressed&#8221; under Properties. You can import your own button images following the procedure for importing the CAD model. Play around with the Toggle Button&#8217;s properties to your heart&#8217;s content.</p>



<p class="wp-block-paragraph"><em>Importing Data from ThingWorx</em></p>



<p class="wp-block-paragraph">There are several widgets available for displaying values. You can use 3D labels and&nbsp;gauges, or 2D gauges and value displays. Once you&#8217;ve selected your widget, you&#8217;ll need to connect the value to the ThingWorx Data. On the right-hand side, there is a tab called &#8220;External Data&#8221;. Click on the plus sign and you&#8217;ll be taken to a search engine as shown below.</p>



<p class="wp-block-paragraph"><p style="text-align: center;"><img decoding="async" alt="How to find your ThingWorx things in Vuforia Studio" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Finding-Things-Vuforia-Studio.png"></p></p>



<ol class="wp-block-list">
<li>Use the top left search engine&nbsp;to find&nbsp;your Thing by its name.</li>



<li>Click the blue right arrow.&nbsp;</li>



<li>In &#8220;Filter Services&#8221;, type &#8220;GetPropertyValues&#8221; and click the blue plus symbol when it pops up. &nbsp;It should now be added to &#8220;External Data&#8221;.</li>



<li>Close out of the search window.</li>



<li>Expand &#8220;External Data&#8221;.&nbsp;</li>



<li>Expand &#8220;Configurations&#8221;.</li>



<li>Select &#8220;Invoke on Startup&#8221;, and &#8220;Auto-Refresh&#8221;.</li>



<li>Change the Auto-Refresh rate to something that fits your project (I used 1 second).</li>



<li>Go to &#8220;Current Selected Item&#8221; to get a list of all your available properties.&nbsp;</li>



<li>Drag the blue&nbsp;cross icon from the desired property over to the&nbsp;blue circle beside &#8220;Value&#8221; on your 2D/3D widget.&nbsp;</li>
</ol>



<p class="wp-block-paragraph">This will cause the widget to show the value of the&nbsp;property from the ThingWorx Foundation platform. Repeat the last two steps&nbsp;for all of your widgets.&nbsp;</p>



<p class="wp-block-paragraph"><em>Publish Your Experience</em></p>



<p class="wp-block-paragraph">In order to save and publish your experience, you&#8217;ll need to associate a ThingMark to your experience.&nbsp; &nbsp;</p>



<ol class="wp-block-list">
<li>Under 3D view, drag a ThingMark widget (under &#8220;Views&#8221; in the left hand column)&nbsp;into your environment.</li>



<li>Under &#8220;Application Parameters&#8221;, drag the blue cross icon&nbsp;next to ThingMark to the blue circle next to ThingMark under the Properties &nbsp;column for your ThingMark widget.&nbsp;</li>



<li>Change the number to match the number of the ThingMark you&#8217;ll be using for the experience (it&#8217;ll be the name of the file in your ThingMark folder given to you with the pilot program).</li>



<li>Adjust the ThingMark widget&#8217;s location in your 3D canvas so that it is in the same manner it will be placed in real life.</li>
</ol>



<p class="wp-block-paragraph">Now go to &#8220;Experience&#8221; under Configurations. Give your experience a name in the &#8220;Title&#8221; box and retype your ThingMark number from before.</p>



<p class="wp-block-paragraph">Now that everything is set up, it&#8217;s time to save your experience and publish it. Click on &#8220;Save&#8221; in the top left corner, then click on &#8220;Publish&#8221;. Once it has successfully published, your AR experience is ready to be viewed on a smartphone or tablet with the Vuforia View Enterprise application downloaded.</p>



<h2 id="h-vuforia-view-enterprise-nbsp" class="wp-block-heading">Vuforia View Enterprise&nbsp;</h2>



<p class="wp-block-paragraph">&nbsp;</p>



<p class="wp-block-paragraph">Almost finished! The last step is to download Vuforia View Enterprise onto your smartphone or tablet. Once you have it downloaded, open up the application,&nbsp;go to settings, and type your service URL. Now print the ThingMark that you&nbsp;used in Vuforia Studio and scan it with your smartphone or tablet. Open up your experience and enjoy your new augmented reality!<span style="text-align: center;">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span></p>



<p class="wp-block-paragraph"><strong><a href="https://static.dmcinfo.com/services/embedded-development-and-embedded-programming"><span style="text-align: center;">Learn more about DMC&#8217;s Custom Hardware and Software development.</span></a></strong></p>
<p>The post <a href="https://static.dmcinfo.com/blog/25084/creating-an-augmented-reality-ar-demo-with-the-vuforia-studio-pilot-program/">Creating an Augmented Reality (AR) Demo with the Vuforia Studio Pilot Program</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>CTA Bus Tracking with the Raspberry Pi</title>
		<link>https://static.dmcinfo.com/blog/28278/cta-bus-tracking-with-the-raspberry-pi/</link>
		
		<dc:creator><![CDATA[DMC]]></dc:creator>
		<pubDate>Mon, 08 Jul 2013 09:58:20 +0000</pubDate>
				<category><![CDATA[Embedded Development & Programming]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[IoT]]></category>
		<category><![CDATA[SDK]]></category>
		<guid isPermaLink="false">https://static.dmcinfo.com/blog/28278/cta-bus-tracking-with-the-raspberry-pi/</guid>

					<description><![CDATA[<p>I&#8217;ve never been much of a morning person; some days, the snooze button on my alarm clock works&#160;harder than I do. I also like to take public transit to work as often as possible. An unfortunate side effect of my erratic waking habits is that an extra 30 second delay in leaving sometimes results in [&#8230;]</p>
<p>The post <a href="https://static.dmcinfo.com/blog/28278/cta-bus-tracking-with-the-raspberry-pi/">CTA Bus Tracking with the Raspberry Pi</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">I&#8217;ve never been much of a morning person; some days, the snooze button on my alarm clock works&nbsp;harder than I do. I also like to take public transit to work as often as possible. An unfortunate side effect of my erratic waking habits is that an extra 30 second delay in leaving sometimes results in missing the bus &#8211; and arriving (another) 10 minutes late to the office. Recently, I pulled my <a href="http://www.raspberrypi.org/faqs" target="_blank">Raspberry Pi</a> out of storage and picked up a <a href="http://www.amazon.com/gp/product/B0045IIZKU/ref=oh_details_o00_s00_i00?ie=UTF8&amp;psc=1" target="_blank">cheap TFT display</a> and set out to cure my morning woes.</p>



<p class="wp-block-paragraph"><strong>Project Goals</strong></p>



<p class="wp-block-paragraph">My goal for this project was to create a simple dashboard that, at a quick glance, could indicate how urgently I needed to leave my apartment and get down to the bus stop. The 3.5&#8243; TFT display is quite small, and even up close it can be somewhat difficult to read text, so I decided to use a basic color coding scheme instead of displaying the number of minutes left. As an added benefit, this style of display would still be perfectly readable even without my contacts in or glasses on &#8211; a common theme of a rushed morning.</p>



<p class="wp-block-paragraph">The hardware platform needed to have a composite video output as well as web access to get real-time bus arrival information from the online data source. To speed up development, I wanted to use a device that bundled these features together and supported programming environments with GUI building tools. Developing in <a href="http://python.org/" target="_blank">Python </a>on a Raspberry Pi fit all of these requirements.</p>



<p class="wp-block-paragraph">For those who aren&#8217;t familiar with the Raspberry Pi platform, I would highly recommend buying one and experimenting with it. In essence, it is a very low-cost ($25 and $35 for the available models), credit-card sized computer equipped with USB, HDMI, and Ethernet capability. It has no on-board memory, but instead boots from an SD card, which makes swapping between different operating systems and applications incredibly simple. It is fast enough to output High-Definition video and audio (many people use it as a cheap home theater PC running <a href="http://wiki.xbmc.org/?title=Raspberry_Pi" target="_blank">XBMC</a>) and also has a prototyping area with General Purpose I/O pins that can be accessed directly by application software. In short, it&#8217;s a hacker&#8217;s dream and perfect for this project.</p>



<p class="wp-block-paragraph">For the Operating System, I decided to go with one of the most popular choices, <a href="https://www.lenovo.com/us/en/glossary/what-is-raspbian/?orgRef=https%253A%252F%252Fwww.google.com%252F" target="_blank" rel="noreferrer noopener">Raspbian</a>. Raspbian is a port of the popular Debian Wheezy OS, and has support for a tremendous variety of software packages and programming languages. To get started, I<a href="http://elinux.org/RPi_Easy_SD_Card_Setup" target="_blank"> prepared my SD card</a> with the latest version of Raspbian, <a href="http://elinux.org/RPi_Remote_Access" target="_blank">configured my machine for remote access</a> via openssh, and then set up <a href="http://elinux.org/RPi_Remote_Access#Running_a_remote_GUI" target="_blank">X11 forwarding</a> to view GUI windows remotely from <a href="http://www.chiark.greenend.org.uk/~sgtatham/putty/" target="_blank">puTTY</a>. Time to start development!</p>



<p class="wp-block-paragraph"><strong>Creating a Skeleton GUI Application</strong></p>



<p class="wp-block-paragraph">Although we&#8217;re not creating a very <a href="//www.youtube.com/watch?v=hkDD03yeLnU" target="_blank">complex GUI application</a>, I&#8217;ve always found that creating a skeleton application is a great starting point for simple projects. Functionality can be added incrementally, as opposed to coding everything up front, and then debugging later.</p>



<p class="wp-block-paragraph">There is a wide variety of GUI toolkits available that play nicely with the Raspberry Pi. I quickly decided to use the <a href="http://en.wikipedia.org/wiki/Tk_%28framework%29" target="_blank">Tk Framework</a>, partially because I&#8217;ve used it successfully in the past, and partially because there is a Python package that interfaces with Tk called <a href="http://wiki.python.org/moin/TkInter" target="_blank">TkInter</a> that is well-documented and easy to use.</p>



<p class="wp-block-paragraph">The code for a basic Python/TkInter window with a programmatically settable background color is criminally simple:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">Python</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>from tkinter import *

if __name__ == '__main__':
    root = Tk()
    root.configure(background='red')
    root.geometry("640x480")
    root.mainloop()</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #C586C0">from</span><span style="color: #D4D4D4"> tkinter </span><span style="color: #C586C0">import</span><span style="color: #D4D4D4"> *</span></span>
<span class="line"></span>
<span class="line"><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">__name__</span><span style="color: #D4D4D4"> == </span><span style="color: #CE9178">&apos;__main__&apos;</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">    root = Tk()</span></span>
<span class="line"><span style="color: #D4D4D4">    root.configure(</span><span style="color: #9CDCFE">background</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&apos;red&apos;</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">    root.geometry(</span><span style="color: #CE9178">&quot;640x480&quot;</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">    root.mainloop()</span></span></code></pre></div>



<p class="wp-block-paragraph">The application creates a Tk window called <span style="font-family: Verdana;">root</span> that has a background color of red and is sized to 640&#215;480 to match the resolution of the TFT display. The code above is targeted for Python 3.3. If Python 2.7 is used, the first <span style="font-family: Verdana;">import</span> line will throw an exception. The TkInter package name changed between these versions. To resolve the error, use the following instead for the import line:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">Python</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>from Tkinter import *</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #C586C0">from</span><span style="color: #D4D4D4"> Tkinter </span><span style="color: #C586C0">import</span><span style="color: #D4D4D4"> *</span></span></code></pre></div>



<p class="wp-block-paragraph">With the skeleton project working, it&#8217;s time to color code the background based on actual bus arrival times.</p>



<p class="wp-block-paragraph"><strong>Bus Arrival Prediction</strong></p>



<p class="wp-block-paragraph">The <a href="http://www.transitchicago.com/" target="_blank">Chicago Transit Authority</a> (CTA), which is the mass transit operator in Chicago, has a great developer API that provides access to real-time bus and train data. Some time back, I applied for a developer API key on a whim and checked out the capabilities of the system. It turns out that the available data matches nicely with the requirements for this project. Every CTA bus has an on-board device that communicates time-synchronized location data back to a central service every minute, and that central service provides estimates of arrival times for each bus, as well as notifications of delays and special service bulletins.</p>



<p class="wp-block-paragraph">As a bonus, the API is very easy to use. To receive, for example, bus arrival predictions for <a href="http://goo.gl/maps/NkGIY" target="_blank">bus stop 6013</a> (the southbound Ashland/#9 bus at Webster, which one might use to get to the Clybourn Metra train station from the DMC office), you make the following HTTP GET:</p>



<pre class="wp-block-code has-d-4-d-4-d-4-color has-text-color has-875-rem-font-size"><code>http:&#47;&#47;www.ctabustracker.com/bustime/api/v1/getpredictions?key=&#91;APIKEY]&amp;stpid=6013</code></pre>



<p class="wp-block-paragraph">I&#8217;ve replaced my API key with [APIKEY], but with a valid one inserted, the response will be a well-formed XML document with a schema that can be obtained from the <a href="http://www.transitchicago.com/developers/bustracker.aspx" target="_blank">CTA Developer documentation</a>. Below is the document tree as displayed in Firefox.</p>



<p class="wp-block-paragraph"><p style="text-align: center;"><img decoding="async" alt="" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/XML-Prediction-Response.png">&nbsp;</p></p>



<p class="wp-block-paragraph">I found a very handy Python library called <em>Requests</em> that wraps the built-in python web libraries and dramatically simplifies HTTP functionality. Using this library, I only needed a single line to make this GET and retrieve the XML data:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">Python</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>r = requests.get("http://www.ctabustracker.com/bustime/api/v1/getpredictions?key=" + apiKey + "&amp;rt=" + homeRt + "&amp;stpid=" + homeStpid</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">r = requests.get(</span><span style="color: #CE9178">&quot;http://www.ctabustracker.com/bustime/api/v1/getpredictions?key=&quot;</span><span style="color: #D4D4D4"> + apiKey + </span><span style="color: #CE9178">&quot;&amp;rt=&quot;</span><span style="color: #D4D4D4"> + homeRt + </span><span style="color: #CE9178">&quot;&amp;stpid=&quot;</span><span style="color: #D4D4D4"> + homeStpid</span></span></code></pre></div>



<p class="wp-block-paragraph">To make the request easier to read, I created global string variables in the Python program that contain the HTTP GET arguments and are concatenated together to form the entire URL. The structure contains the content of the response as well as a host of other information that we don&#8217;t need for the first iteration of this application.</p>



<p class="wp-block-paragraph">Since the response from the CTA web API is a well-formed XML document, I needed an XML parser to extract out the arrival time of the next bus from the bus stop.&nbsp; Python includes a package called ElementTree which can read an XML document into memory and programmatically read/write attributes and node content.</p>



<p class="wp-block-paragraph">The XML response for the getpredictions API query typically returns multiple buses and predictions. Our application, however, really only cares about the bus that will arrive the soonest. So, the strategy when parsing this XML document will be the following:</p>



<ol class="wp-block-list">
<li>Check to make sure the API hasn&#8217;t reported an error (the schema specifies how an error will be reported, so this can be done reliably)</li>



<li>Check to make sure at least one prediction has been reported</li>



<li>Get the predicted arrival time and current system time from the bus that will arrive the soonest</li>



<li>Calculate the amount of time, in minutes, until the next arrival</li>
</ol>



<p class="wp-block-paragraph">The code for this parsing function looks like the snippet below. Note that I&#8217;m using the DateTime package to handle the time interval calculations without reinventing the wheel.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">Python</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>def parseXmlResponse(resp):
    treeRoot = ET.fromstring(resp)
    predList = treeRoot.findall('prd')

    # Check for an error response first
    if (treeRoot.find('error') == "None") or (len(predList) == 0):
        print("CTA API Reported Error")
        root.configure(background='gray')
        return -1
    else:
        # Get the time difference in minutes
        currTime = predList&#91;0&#93;.find('tmstmp').text
        predTime = predList&#91;0&#93;.find('prdtm').text
        t1 = datetime.datetime.strptime(currTime.split(' ')&#91;1&#93;,'%H:%M')
        t2 = datetime.datetime.strptime(predTime.split(' ')&#91;1&#93;,'%H:%M')
        arrMin = (t2 - t1).seconds / 60.0

        return arrMin</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">def</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">parseXmlResponse</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">resp</span><span style="color: #D4D4D4">):</span></span>
<span class="line"><span style="color: #D4D4D4">    treeRoot = ET.fromstring(resp)</span></span>
<span class="line"><span style="color: #D4D4D4">    predList = treeRoot.findall(</span><span style="color: #CE9178">&apos;prd&apos;</span><span style="color: #D4D4D4">)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955"># Check for an error response first</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (treeRoot.find(</span><span style="color: #CE9178">&apos;error&apos;</span><span style="color: #D4D4D4">) == </span><span style="color: #CE9178">&quot;None&quot;</span><span style="color: #D4D4D4">) </span><span style="color: #569CD6">or</span><span style="color: #D4D4D4"> (</span><span style="color: #DCDCAA">len</span><span style="color: #D4D4D4">(predList) == </span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">):</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #DCDCAA">print</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;CTA API Reported Error&quot;</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">        root.configure(</span><span style="color: #9CDCFE">background</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&apos;gray&apos;</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> -</span><span style="color: #B5CEA8">1</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">else</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #6A9955"># Get the time difference in minutes</span></span>
<span class="line"><span style="color: #D4D4D4">        currTime = predList&#91;</span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">&#93;.find(</span><span style="color: #CE9178">&apos;tmstmp&apos;</span><span style="color: #D4D4D4">).text</span></span>
<span class="line"><span style="color: #D4D4D4">        predTime = predList&#91;</span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">&#93;.find(</span><span style="color: #CE9178">&apos;prdtm&apos;</span><span style="color: #D4D4D4">).text</span></span>
<span class="line"><span style="color: #D4D4D4">        t1 = datetime.datetime.strptime(currTime.split(</span><span style="color: #CE9178">&apos; &apos;</span><span style="color: #D4D4D4">)&#91;</span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4">&#93;,</span><span style="color: #CE9178">&apos;%H:%M&apos;</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">        t2 = datetime.datetime.strptime(predTime.split(</span><span style="color: #CE9178">&apos; &apos;</span><span style="color: #D4D4D4">)&#91;</span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4">&#93;,</span><span style="color: #CE9178">&apos;%H:%M&apos;</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">        arrMin = (t2 - t1).seconds / </span><span style="color: #B5CEA8">60.0</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> arrMin</span></span></code></pre></div>



<p class="wp-block-paragraph">Now, all we have to do is change the background color of the window based on the number of minutes left until the bus arrives. I added the following code just before the return statement of the <span style="font-family: Verdana;">parseXmlResponse</span> function:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">Python</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>        # Color the background appropriately depending on
        # the amount of time left before the bus arrives
        if (arrMin >= 8) or (arrMin &lt;= 2):
            root.configure(background='red')
        elif arrMin &lt; 5:
            root.configure(background='yellow')
        else:
            root.configure(background='green')</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">        </span><span style="color: #6A9955"># Color the background appropriately depending on</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #6A9955"># the amount of time left before the bus arrives</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (arrMin &gt;= </span><span style="color: #B5CEA8">8</span><span style="color: #D4D4D4">) </span><span style="color: #569CD6">or</span><span style="color: #D4D4D4"> (arrMin &lt;= </span><span style="color: #B5CEA8">2</span><span style="color: #D4D4D4">):</span></span>
<span class="line"><span style="color: #D4D4D4">            root.configure(</span><span style="color: #9CDCFE">background</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&apos;red&apos;</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">elif</span><span style="color: #D4D4D4"> arrMin &lt; </span><span style="color: #B5CEA8">5</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">            root.configure(</span><span style="color: #9CDCFE">background</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&apos;yellow&apos;</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">else</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">            root.configure(</span><span style="color: #9CDCFE">background</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&apos;green&apos;</span><span style="color: #D4D4D4">)</span></span></code></pre></div>



<p class="wp-block-paragraph"><strong>Automatic Updates</strong></p>



<p class="wp-block-paragraph">Despite all of the code we&#8217;ve implemented so far to get the predicted times from the CTA web API and shade the background of the screen accordingly, at the moment, nothing will ever kick off the updates <a href="http://www.sadtrombone.com/" target="_blank"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f641.png" alt="🙁" class="wp-smiley" style="height: 1em; max-height: 1em;" /></a></p>



<p class="wp-block-paragraph">Luckily, there is a lot of support in Python for threading, and we can utilize this functionality to create a thread that runs the update code on a regular interval.</p>



<p class="wp-block-paragraph">The first thing we need to do is create a class that inherits from the Threading.Thread class and knows which function to call when the thread is started. I have called the thread TimeUpdater, and the code looks like the following:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">Python</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>class TimeUpdater(threading.Thread):
    def __init__(self, updateFn):
        threading.Thread.__init__(self)
        self.runnable = updateFn

    def run(self):
        self.runnable()</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">class</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">TimeUpdater</span><span style="color: #D4D4D4">(</span><span style="color: #4EC9B0">threading</span><span style="color: #D4D4D4">.</span><span style="color: #4EC9B0">Thread</span><span style="color: #D4D4D4">):</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">def</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">__init__</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">self</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">updateFn</span><span style="color: #D4D4D4">):</span></span>
<span class="line"><span style="color: #D4D4D4">        threading.Thread.</span><span style="color: #DCDCAA">__init__</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">self</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">self</span><span style="color: #D4D4D4">.runnable = updateFn</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">def</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">run</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">self</span><span style="color: #D4D4D4">):</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">self</span><span style="color: #D4D4D4">.runnable()</span></span></code></pre></div>



<p class="wp-block-paragraph">The class is simple. Now, we need to write the code that will be executed at the given interval. The strategy I used was to create a function with an infinite loop of the following:</p>



<ol class="wp-block-list">
<li>Query the CTA API</li>



<li>Parse the response XML and update background color</li>



<li>(Optional) print some debug information to the console</li>



<li>Sleep for the update interval time</li>
</ol>



<p class="wp-block-paragraph">The code looks like the following:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">Python</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>def updateArrivalTime():
    while True:
        r = requests.get("http://www.ctabustracker.com/bustime/api/v1/getpredictions?key=" +
                         apiKey + "&amp;rt=" + homeRt + "&amp;stpid=" + homeStpid)
        parseXmlResponse(r.content)
        print('Data Updated at ' + str(time.time()))
        time.sleep(updateInterval)</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">def</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">updateArrivalTime</span><span style="color: #D4D4D4">():</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">while</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">True</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">        r = requests.get(</span><span style="color: #CE9178">&quot;http://www.ctabustracker.com/bustime/api/v1/getpredictions?key=&quot;</span><span style="color: #D4D4D4"> +</span></span>
<span class="line"><span style="color: #D4D4D4">                         apiKey + </span><span style="color: #CE9178">&quot;&amp;rt=&quot;</span><span style="color: #D4D4D4"> + homeRt + </span><span style="color: #CE9178">&quot;&amp;stpid=&quot;</span><span style="color: #D4D4D4"> + homeStpid)</span></span>
<span class="line"><span style="color: #D4D4D4">        parseXmlResponse(r.content)</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #DCDCAA">print</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&apos;Data Updated at &apos;</span><span style="color: #D4D4D4"> + </span><span style="color: #4EC9B0">str</span><span style="color: #D4D4D4">(time.time()))</span></span>
<span class="line"><span style="color: #D4D4D4">        time.sleep(updateInterval)</span></span></code></pre></div>



<p class="wp-block-paragraph">Only one more step remains: we have to start the update thread when the application is started. I created a function to handle this and called it just before the call to the root window&#8217;s mainloop function:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">Python</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>def startUpdateThread():
    updateThread = TimeUpdater(updateArrivalTime)
    updateThread.start()</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">def</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">startUpdateThread</span><span style="color: #D4D4D4">():</span></span>
<span class="line"><span style="color: #D4D4D4">    updateThread = TimeUpdater(updateArrivalTime)</span></span>
<span class="line"><span style="color: #D4D4D4">    updateThread.start()</span></span></code></pre></div>



<p class="wp-block-paragraph"><strong>Optimization</strong></p>



<p class="wp-block-paragraph"><a href="//www.youtube.com/watch?v=O1fHxPY3TJo" target="_blank">What we&#8217;ve got here is&#8230;.</a> an application that fits all of the design objectives that we started with. However, there was one thing that really bothered me throughout the development of this Python code: hard-coded data. The API Key, home bus stop number, update interval, time delta thresholds for the background colors, etc.. they&#8217;re all coded as magic numbers. Even with descriptive variable names, I don&#8217;t like the idea of needing to edit the application source in order to change the user&#8217;s current location and display preferences.</p>



<p class="wp-block-paragraph">With a little searching, I was able to discover the <a href="http://docs.python.org/2/library/configparser.html" target="_blank">ConfigParser </a>library, which is bundled along with Python. This module handles the import and parsing of config files that can be bundled with the Python application. When I originally set up my Raspberry Pi, I enabled file transfer over ssh using <a href="http://en.wikipedia.org/wiki/SSHFS" target="_blank">sshfs</a>. Using this, I can update the configuration of the dashboard application over the web without ever plugging a keyboard into the Pi.</p>



<p class="wp-block-paragraph">Let&#8217;s first take a look at the structure of the configuration file that ConfigParser will look for. I (somewhat arbitrarily) separated the parameters into two subheadings: <em>Tracker Settings </em>and <em>Color Settings. </em></p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">INI</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>&#91;Tracker Settings&#93;
api-key = APIKEY
home-stpid = 6013
home-rt    = 9
update-interval = 30.0

&#91;Color Settings&#93;
too-fast = 2.0
too-slow = 8.0
just-right = 5.0</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">&#91;Tracker Settings&#93;</span></span>
<span class="line"><span style="color: #569CD6">api-key</span><span style="color: #D4D4D4"> = APIKEY</span></span>
<span class="line"><span style="color: #569CD6">home-stpid</span><span style="color: #D4D4D4"> = 6013</span></span>
<span class="line"><span style="color: #569CD6">home-rt</span><span style="color: #D4D4D4">    = 9</span></span>
<span class="line"><span style="color: #569CD6">update-interval</span><span style="color: #D4D4D4"> = 30.0</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">&#91;Color Settings&#93;</span></span>
<span class="line"><span style="color: #569CD6">too-fast</span><span style="color: #D4D4D4"> = 2.0</span></span>
<span class="line"><span style="color: #569CD6">too-slow</span><span style="color: #D4D4D4"> = 8.0</span></span>
<span class="line"><span style="color: #569CD6">just-right</span><span style="color: #D4D4D4"> = 5.0</span></span></code></pre></div>



<p class="wp-block-paragraph">The ConfigParser module reads in the entire config file and then can be searched explicitly for parameters in specific headings. So, for example, to get the update interval of the application, I can execute the following line:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">Python</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>updateInterval = config.getfloat('Tracker Settings', 'update-interval')</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">updateInterval = config.getfloat(</span><span style="color: #CE9178">&apos;Tracker Settings&apos;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&apos;update-interval&apos;</span><span style="color: #D4D4D4">)</span></span></code></pre></div>



<p class="wp-block-paragraph">It didn&#8217;t take much time at all to get this working in my application, and I was able to do a little refactoring as well. I created a function called startApp that reads in the relevant config parameters and kicks off the update thread. This is called immediately after the application starts as before.</p>



<p class="wp-block-paragraph"><strong>Show Me the Money!</strong></p>



<p class="wp-block-paragraph">With the application fully coded, it&#8217;s time to test it out on the Raspberry Pi! If you&#8217;re interested in taking a look at the full code for this project, you can find it at the <a href="https://github.com/dmc-inc" target="_blank" rel="noreferrer noopener">DMC GitHub account</a>. Below is a video I took of the application running alongside the official CTA bus tracker web application to confirm that the data is updating correctly and in real-time (now with 40% more props!). Now I&#8217;ll never be late for another bus again!</p>



<p class="wp-block-paragraph"><iframe frameborder="0" height="315" src="//www.youtube.com/embed/mseVTsifVLU" width="560"></iframe></p>



<p class="wp-block-paragraph"><strong>Future Improvements</strong></p>



<p class="wp-block-paragraph">Like any hobby project, there never seems to be any end to the improvements that can be made. One big improvement that I need to make is to automatically launch the application in a graphical window every time the Raspberry Pi starts. I experimented with this using <a href="https://en.wikipedia.org/wiki/Cron" target="_blank">cron</a>, which is a task scheduler application that exists on Unix-based operating systems (including Raspbian). However, the sticker for me is that you need to start up the X-Window environment first before launching an application that contains a GUI. I&#8217;m sure someone has solved this issue before, and the solution is documented somewhere online.</p>



<p class="wp-block-paragraph">The other thing I&#8217;d like to do is include a display that indicates what the weather will be like during my transit hours (7-9am and 5-7pm). There are many data sources available online, and adding this functionality shouldn&#8217;t require any major new components, since we&#8217;re already doing web API requests, response parsing, and graphical updates!</p>



<p class="wp-block-paragraph">Eventually, I would like to configure this application entirely through the web by hosting a <a href="http://en.wikipedia.org/wiki/Representational_state_transfer" target="_blank">RESTful API</a> on the Raspberry Pi and connecting to it on a web browser. This would probably replace my preferences file and require the addition of a database to store data persistently, although I could take the easy road and edit the configuration file as the preferences are updated. Decisions, decisions!</p>



<p class="wp-block-paragraph">I highly recommend checking out the Raspberry Pi on your own. Happy hacking!</p>



<p class="wp-block-paragraph"><a href="/services/embedded-development-and-embedded-programming">Learn more about DMC&#8217;s embedded development expertise.</a></p>
<p>The post <a href="https://static.dmcinfo.com/blog/28278/cta-bus-tracking-with-the-raspberry-pi/">CTA Bus Tracking with the Raspberry Pi</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Programming Madness National Championship</title>
		<link>https://static.dmcinfo.com/blog/28761/programming-madness-national-championship/</link>
		
		<dc:creator><![CDATA[DMC]]></dc:creator>
		<pubDate>Tue, 25 Sep 2012 13:46:55 +0000</pubDate>
				<category><![CDATA[Culture]]></category>
		<category><![CDATA[and Driver]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[MS Visual Studio/.NET]]></category>
		<category><![CDATA[PC]]></category>
		<category><![CDATA[SDK]]></category>
		<guid isPermaLink="false">https://static.dmcinfo.com/blog/28761/programming-madness-national-championship/</guid>

					<description><![CDATA[<p>Welcome to the Programming Tournament National Championship! For the sake of drama, I was going to make a Tournament Highlights blog first, but I figured that everyone was probably so overly excited that putting off the decision any longer would be inhumane. For anyone coming to the party late, I have spent the last 6 [&#8230;]</p>
<p>The post <a href="https://static.dmcinfo.com/blog/28761/programming-madness-national-championship/">Programming Madness National Championship</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Welcome to the Programming Tournament National Championship! For the sake of drama, I was going to make a <a href="https://static.dmcinfo.com/blog/29116/march-programming-madness-the-bracket/">Tournament Highlights</a> blog first, but I figured that everyone was probably so overly excited that putting off the decision any longer would be inhumane. For anyone coming to the party late, I have spent the last 6 months (or 3 half-lives of Antimony Sb-124) reviewing the positives and negatives of different programming languages that I’ve worked with, pitting them head to head in a <a href="https://www.ncaa.com/march-madness-live/watch" target="_blank" rel="noreferrer noopener">NCAA style tournament</a>.</p>



<p class="wp-block-paragraph">We’ve had <a href="https://static.dmcinfo.com/blog/29039/programming-madness-diving-into-round-2/">a few upsets along the way</a>, but for the most part, the favorites proved <a href="https://static.dmcinfo.com/blog/28859/programming-madness-conference-finals/">why they earned the high seeds</a>. After a last minute video review overturned what looked initially like a C++ victory in the semi-finals, this inaugural championship is between <a href="https://www.microsoft.com/en-us/" target="_blank" rel="noreferrer noopener">Microsoft’s</a> <a href="https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/program-structure/" target="_blank" rel="noreferrer noopener">C# .Net</a> and review beneficiary,&nbsp;<a href="http://en.wikipedia.org/wiki/Sun_Microsystems" target="_blank">Sun Microsystems’</a> / <a href="https://www.oracle.com/" target="_blank" rel="noreferrer noopener">Oracle</a> / <a href="http://arstechnica.com/information-technology/2010/08/oracles-java-lawsuit-undermines-its-open-source-credibility/" target="_blank">Open-Source-Independent</a>, <a href="http://www.java.com/en/download/index.jsp" target="_blank">Java</a>.</p>



<p class="wp-block-paragraph">Amazingly, put perhaps not surprisingly, the architectures and syntax of these 2 platforms is remarkably similar. For a complete look at the similarities, there are a number of <a href="http://www.25hoursaday.com/CsharpVsJava.html" target="_blank">great sites</a> exposed by a simple Google search. Some of these differences are significant, while some are cosmetic, but diving into all of them is well beyond the scope of a simple blog post.</p>



<p class="wp-block-paragraph">Now, admittedly, I have done much more work on C# projects than I have with Java, and my Java experience is strictly from what I’ve done working with Android Development and anything I could learn from the <a href="https://www.amazon.com/Java-1-1-Unleashed-Michael-Morrison/dp/1575212986/ref=sr_1_5?crid=264F73CE94ECB&amp;dib=eyJ2IjoiMSJ9.rUTY5j2BCIEwpwXo8clArVL3uWNjlidpwyzxwzk0UpdYUCbW9lVWZielk1U4zcWlHModp9p4QOlHZLzdp-aNtj0FzzEKDwh7dLn5J_KPXvX_9YRxifDJm98vigJrK-B1qCsi_X3rQyQjIByVF8cROeiDgKlRrSKykwaCciEHjtemT9Pdu1XAtdic6Q_E3aYeJPusFQiYQw6jHCrYy7OvJkGJliopy3XabglvdSRk7QI.XfFDyeOMYWbJUllncjBwJSIqwmrqO6JxKxGXep1q4DM&amp;dib_tag=se&amp;keywords=java+unleashed&amp;qid=1751297743&amp;sprefix=java+unleashed%2Caps%2C91&amp;sr=8-5" target="_blank" rel="noreferrer noopener">Java Unleashed</a> book I bought back in 1997 (you know, when I was in seventh grade and they had to give you a CD-ROM with the SDK and examples, since AOL dialup was still too slow to download anything real from the new-fangled “Internet” thing.)</p>



<p class="wp-block-paragraph">Jumping from C# into Java, I’ve been perfectly able to make basic Android apps, and all else being equal, I honestly would lean towards Java for the simple reason that it is inherently cross-platform. Like other <a href="https://static.dmcinfo.com/blog/28904/programming-madness-last-of-the-quarter-finals/">cross-platform languages</a>, this means that code I write on my Windows computer can be compiled and run on a Mac without worry. This advantage means that we don’t have to build the same application 3 times to run on Windows, Mac, and Linux devices, a huge business case for commercial software companies. The <a href="http://en.wikipedia.org/wiki/Java_virtual_machine" target="_blank">Java VM mechanism</a> used to achieve this is pretty neat too, even if it does mean that we are constantly getting <a href="http://www.quickmeme.com/meme/3q4z9c/" target="_blank">barraged by Java update requests at startup</a>. C# is making progress here with the <a href="http://www.mono-project.com/Main_Page" target="_blank">Mono Project</a>, but there is still a long way to go to get the same foothold that Java has.</p>



<p class="wp-block-paragraph">So the winner is Java, right? Well, not so fast. C# gets a chance for a rebuttal, and rebut it does. By most accounts, <a href="http://www.25hoursaday.com/CsharpVsJava.html#different" target="_blank">C#</a> is slightly ahead of <a href="http://www.25hoursaday.com/CsharpVsJava.html#wishlist" target="_blank">Java</a> when it comes to features, although both, it seems, have been doing a flip-flop where one adds a useful feature and then the other copies it. The biggest area where I think C# stands out is the integrated usage and implementation of types and classes for each. It might just be because it’s what I’m used to, but the system in C# makes a lot more sense to me than does Java.</p>



<p class="wp-block-paragraph">For example, Java lacks static classes, doesn’t have a tool like LINQ, won’t allow named and optional method inputs, can’t pass inputs as references, doesn’t integrate arrays and collections, and has only watered down support for Generics. Project file management also seems better in C#, with conditional compilation flags and a level of abstraction between assemblies and files and between files and classes. Now, I know that each of these are subjective features, and you can probably even argue that some features are intentionally left out of Java, but I personally have become accustomed to the C# programming style and think that it makes sense.</p>



<p class="wp-block-paragraph">The bottom line is that both C# and Java are excellent, high level languages, with many similarities and a few individual strong points. I think that environment has a strong impact on which you prefer, but for me, being in a strongly <a href="/about/partners">Microsoft-centric workplace</a>, C# is my go to language. Therefore, strongly weighing my own opinion of my own opinion, in a wild game, with a controversial play, at the very last second, on a strongly contested Hail Mary, C# wins in what will safely go down as an Instant Classic.</p>



<p class="wp-block-paragraph"><a href="https://static.dmcinfo.com/blog/28859/programming-madness-conference-finals/">Semi Final Flashback</a></p>



<p class="wp-block-paragraph"><a href="https://static.dmcinfo.com/blog/29116/march-programming-madness-the-bracket/">Relive the Excitement</a></p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Nerdament-4_0.png" alt=""/></figure>
<p>The post <a href="https://static.dmcinfo.com/blog/28761/programming-madness-national-championship/">Programming Madness National Championship</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Create a Photo Booth with Your Canon DSLR</title>
		<link>https://static.dmcinfo.com/blog/29304/create-a-photo-booth-with-your-canon-dslr/</link>
		
		<dc:creator><![CDATA[Jason Mayes]]></dc:creator>
		<pubDate>Mon, 07 Nov 2011 15:20:11 +0000</pubDate>
				<category><![CDATA[Culture]]></category>
		<category><![CDATA[and Driver]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[SDK]]></category>
		<guid isPermaLink="false">https://static.dmcinfo.com/blog/29304/create-a-photo-booth-with-your-canon-dslr/</guid>

					<description><![CDATA[<p>I attended a wedding a few months back where the bride and groom had rented a photo booth. With a combination of props and wine, there were many great photo strips being printed and passed around and it quickly turned into quite the contest. Naturally, I won. It seemed like a great idea – the [&#8230;]</p>
<p>The post <a href="https://static.dmcinfo.com/blog/29304/create-a-photo-booth-with-your-canon-dslr/">Create a Photo Booth with Your Canon DSLR</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">I attended a wedding a few months back where the bride and groom had rented a photo booth. With a combination of props and wine, there were many great photo strips being printed and passed around and it quickly turned into quite the contest. Naturally, I won. It seemed like a great idea – the guests were really enjoying themselves and the bride and groom kept a copy of each strip to put into a photo album documenting their big day.<br> <br> After the wedding, I was talking with some friends who had done something similar and mentioned the cost involved with renting a photo booth. It seemed <a href="http://www.rentphotobooths.com/">ridiculously high</a>! After all, it&#8217;s just a simple camera taking a few photos and printing them out on a photo printer! This got me thinking though… “I have a camera, I have a printer, and I have Visual Studio… I should have a photo booth at my house!”<br> <br> And so an idea was born.<br> <br> Wanting to do as little work as possible, I started my quest for a photo booth on Google. After a few quick searches, I was very pleased to find that Canon, the maker of two of my camera’s, offered <a href="http://en.wikipedia.org/wiki/Software_development_kit">SDK’s</a> for development for both their point-and-shoots and their DSLR’s.  Thinking I could multi-task and expand this into a custom <a href="http://www.google.com/search?hl=en&amp;sugexp=ernk_lssbd,lf%3D90,ss%3D94,se%3D98&amp;cp=11&amp;gs_id=1j&amp;xhr=t&amp;q=time+lapse+photography&amp;biw=1472&amp;bih=801&amp;gs_sm=&amp;gs_upl=&amp;bav=on.2,or.r_gc.r_pw.,cf.osb&amp;um=1&amp;ie=UTF-8&amp;tbm=isch&amp;source=og&amp;sa=N&amp;tab=wi">time-lapse photography </a>application (which will surely offer me hours of entertainment at a later time), I decided to run with the DSLR option. After a quick email to Canon <a href="http://usa.canon.com/cusa/consumer/standard_display/sdk_homepage">requesting their Canon Digital Camera SDK</a>, I was in business.<br> <br> While the SDK provides all the DLL’s you will need to develop Windows based applications, it is, unfortunately, primarily written in C. They are kind enough to provide a simple class in C# that, while really just a starting point, will allow you to get started. Not wanting to develop my own  wrapper, I again took to Google to see if anyone else would be kind enough to share their work. Luckily, I found two great resources, <a href="http://blog.waynehartman.com/archive/2009/01/07/edsdk-to-remote-control-your-canon-camera.aspx">a blog post and wrapper by Wayne Hartman</a>, and a code project by Christian Graus and Benjamin Liedbad. While both were fantastic resources, Hartman’s wrapper and sample project has very nearly done all of the work already.<br> <br> After getting the demo application up and running, it was a simple matter of creating a new form to function as a UI, adding a few timers and events to take a few pictures, and then resizing the photos and assembling a photo strip. And done! A home made booth for my next Holiday party!<br> <br> Recently, we had a <a href="/latest-thinking/blog/id/811/dmcs-oktoberfest-open-house">DMC Oktoberfest event </a>here at our office. It seemed like a good place to set up a photo booth, so it made its first appearance. Enjoy some of the results!</p>



<p class="wp-block-paragraph">&nbsp;<img decoding="async" alt="" height="383" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/DMCPhotoBooth01.jpg" width="121">&nbsp;<img decoding="async" alt="" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/DMCPhotoBooth02.jpg">&nbsp;<img decoding="async" alt="" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/DMCPhotoBooth04.jpg"></p>



<p class="wp-block-paragraph"><a href="/about">Learn more about DMC&#8217;s company culture.</a></p>
<p>The post <a href="https://static.dmcinfo.com/blog/29304/create-a-photo-booth-with-your-canon-dslr/">Create a Photo Booth with Your Canon DSLR</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
