Thursday, January 18, 2018

Old Phone/Tablet as an Info Board Part 1: IFRAME's and their limitations

This continues our series on making an info screen. Last time, we created a skeleton layout, so let us begin filling it with contents.

As an example, let us try to display current and hourly weather using this webpage:
https://www.theweathernetwork.com/ca/hourly-weather-forecast/ontario/mississauga

Highlighted are regions I'd like to put on the info board.

The most straightforward way of putting something from the third-party website into your own would be an IFRAME tag, of this global format:
<IFRAME scrolling="no" src="..." style="..."></IFRAME>

Now usually you would only need some portion of the website displayed on your screen. Unfortunately, if the contents of your IFRAME is from the third-party website, you cannot interact with its content (with a very few exceptions) due to the commonly accepted same-origin policy. (Annoying as it is in our case, this limitation is what prevents a fair amount of malicious attacks.)

However, the desired portion of the website can be extracted via re-positioning the iframe using this negative margin trick:

style="margin-left: -(XXX)px; margin-top: -(YYY)px;"

To zoom in or out on the corresponding website, the only way is to use CSS transform property, like so:

<div id="weather1" class="basic" style="position: relative; left: 5px; top: 10px; width: 500px; height: 180px;">
<iframe scrolling="no" src="https://www.theweathernetwork.com/ca/hourly-weather-forecast/ontario/mississauga" 
style=" -webkit-transform: scale(0.72);  -webkit-transform-origin: 0 0;
 transform: scale(0.72);  transform-origin: 0 0; 
        margin-left: -20px; margin-top: -200px; 
 border: 0px none; height: 8120px; width: 750px;"> 
</iframe></div>

<div id="weather2" class="basic" style="position: relative; left: 5px; top: 20px; width: 500px; height: 200px;">
<iframe scrolling="no" src="https://www.theweathernetwork.com/ca/hourly-weather-forecast/ontario/mississauga" 
style=" -webkit-transform: scale(0.72);  -webkit-transform-origin: 0 0;
 transform: scale(0.72);  transform-origin: 0 0; 
        margin-left: -30px; margin-top: -690px; 
 border: 0px none; height: 8120px; width: 750px;"> 
</iframe></div>
(The -webkit- prefix is needed for browsers like the PlayBook's (or Safari); some other browsers may need other prefixes.)
This gives us something like:


As you can see, this method is very easy to code and there is no need (and no possibility for that matter) to do any rearrangement of the displayed information. The target website takes care of that for you.


Two major pitfalls (besides the above mentioned inability to interact with the iframe contents) are:
  1. Manual adjustment of the margin is very unreliable. Granted, other methods are prone to failing once the target web site undergoes a redesign, but here even a minor change of the layout would screw the placement of your desired content and require re-adjustment. What is worse, this may happen even without a website redesign proper, due to some external content (e.g. ads) affecting the elements' location and sizing. So your screen can intermittently show the wrong content, and may need frequent readjustments.
  2. Even though most of the iframe's target website will be hidden, it will still be loaded and processed (all its scripts, embedded videos, plugins, and ads included), which makes it very heavy on the client browser (especially on older hardware such as the PlayBook). Using transformation makes matters much worse (I guess it may even force the browser to have to "invisibly" render the entire page - how else would the browser know how to scale it?). In my testing, the above example rendered my PlayBook rather unresponsive. 
So, this method would be prohibitively slow for many practically relevant cases. Still, it is a simple and viable method so long as the target URL is rather lightweight and not too loaded with dynamic HTML or embedded media. A good candidate is a mobile webpage or a page specially designed to be embedded, like this: 

<div id="weather1" class="basic" style="position: relative; left: 10px; top: 10px; width: 300; height: 185px; background: white;">
<iframe scrolling="no" src="http://weather.gc.ca/wxlink/wxlink.html?cityCode=on-24&lang=e" allowtransparency="true" 
 style="border: 0px none; height: 185px; width: 300px;"></iframe>
</div>



Friday, January 12, 2018

Old Phone/Tablet as an Info Board Intro: Backstory and Basics

Some time in the past, my loving wife gave me a Blackberry PlayBook for my birthday. As I don't use it much these days (my smartphone has become more versatile and powerful), and would loathe to part with it (it is barely worn and beautiful, and has sentimental value), I would like to give it a second life. 

So in a series of posts I am going to log how I turn the Playbook into an info board: an always-on, always up to date information screen next to the front door, showing some information such as the status of my commute and today's weather. 

Why an information screen in favor of other alternatives? For the same reasons they use departure boards at airports and transit stations: it is the fastest and the least disruptive way to get the important information. You can use it with your hands full (unlike your phone), and you don't have to stand there listening for a robotic voice (unlike Hey Google / Alexa / Siri).

Like so: (and yes, this is a sneak peek into the beta version of the end result):



The DiskStation server I have at home.
Rather than getting the SDK and writing an app (long!!!), I decided to make a web page and host it on my DiskStation (a network attached storage which has a web server function). This approach is much more versatile since it is not limited to the PlayBook or Blackberry. In fact, there will be very few PlayBook-specific points here (mostly limitations: PlayBook uses a rather old implementation of Webkit, and its processor is, by the modern web standards, not the fastest).

On the contrary, the procedures given here should be helpful for many other devices - old iPads, old Android tables, old smartphones (even though a smartphone has a smaller screen and there will be less info that it can meaningfully display) and perhaps something even more exotic like old monitors hooked to something like a Raspberry Pi.

In fact, when the screen is ready, anyone at home can access it from their desktop or phone if they need the info but don't feel like physically going downstairs.


So, to get the job done, we will be combining server-side programming (PHP) and client-side programming (JavaScript / jQuery).

Let's get started by designing an interface:

<html>
<head>
    <title>Info Screen</title>
  <style>
   div.background {background: black; fallback: linear-gradient(180deg, rgb(0,0,0), rgb(25,25,25)); position: absolute; left:0; top:0; height: 560px; width: 1024px; }
   div.basic { background-color: white; border: 1px solid rgb(255,255,255); border-radius: 15px; overflow: hidden; padding: 5px;}
   div.saver {filter:invert(100%);-webkit-filter:invert(100%);}
   div.info { text-align: center; vertical-align: middle;  font-family: "Arial", Helvetica, Sans-Serif; font-size:22px}
  .element {font-size: 12px; text-align: center;}
  .large{background-color: #ffffee;width:650px;height:400px;float:left;}
  </style>
</head>

<body> <div class="background">
<div id="status" class="basic info" style="position: absolute; left: 10px; top: 10px; width: 120px; height: 90px; background: #EEFFF8; color: gray; font-size: 12px;"></div>

<div id="weather" class="basic" style="position: absolute; left: 10px; bottom: 190px; width: 120px; height: 240px; background: #EEEEFF;"></div>
<div id="hourly" class="basic info" style="position: absolute; left: 10px; bottom: 10px; width: 990px; height: 160px; background: white;"></div>

<div id="map" class="basic" style="border: none; position: absolute; right: 10px; top: 10px; width: 415px; height: 350px;"></div>
<div id="travel" class="basic info" style="position: absolute; left: 150px; bottom: 190px; width: 415px; height: 60px; background:rgb(255,255,225);"> </div>

<div id="bus" class="basic info" style="position: absolute; left: 150px; bottom: 270px; width: 415px; height: 50px; background:rgb(255,235,235);"> </div>
<div id="train1" class="basic" style="position: absolute; left: 150px; top: 10px; width: 200px; height: 195px; "></div>
<div id="train2" class="basic" style="position: absolute; left: 365px; top: 10px; width: 200px; height: 195px; "></div>

</div>
</body> </html>

Note that the code above describes only the layout of the elements. In the upcoming posts (there will be 3-4 of them) I am going to discuss in detail how to actually fill the interface with contents, as well as how to script its automatic updates.

(On a side note, it looks like we've lived through a shift of paradigm about what good stuff is.

For centuries - and indeed, persisting all the way into the end of the 20th century - the basic idea of all goods was "the good stuff is the stuff that lasts".

Indeed, in a world where changes are slow and manufacturing is scarce, or expensive, or both, this made total sense. Having to replace anything (from your tools of the trade to the pair of shoes you wear) was an extra burden to be avoided if at all possible; ideally, good stuff would last a lifetime and sometimes even outlast its owners.

But nowadays - at least the "modernized countries" world - this has changed. And the biggest change has been the change of pace. Stuff improves much faster than it wears out. Not only that, but also - with the digital stuff in particular - your device is only as good as the software it works with, and if that software outruns your hardware, bad luck.

To summarize this in a metaphor, we became kids again - the digital kids who outgrow their digital clothes before they have any chance of wearing out. We may happen to have the best smartphone in the world today. But in a few years it will be bugged with so many "apps-that-won't update" and "sites-that-take-forever-to-load" and "services-that-no-longer-work" that using this once-perfect gadget would feel like dressing your five-year-old in clothes that were her favorite when she was three.