Home > Designing, Others > How I Built a GPS-Powered Weather Clock With My Old iPhone 4

How I Built a GPS-Powered Weather Clock With My Old iPhone 4

January 17th, 2019 Leave a comment Go to comments

My first smartphone was an iPhone 4s. I remember the excitement of exploring its capabilities at a time when it was the coolest thing around. Eventually, of course, I replaced it with a newer model and the old iPhone, still in mint condition, gathered dust for two years. What a waste!

But was it? It occurred to me that I could repurpose the old iPhone to create a useful weather clock for our hallway.

Who needs Nest anyway?

In the process, I discovered that reusing an old device is not only fun and economical, it can also deepen your understanding of web standards. In this tutorial, I will show how I created a small web page to display the date, time, and current weather conditions based on the current GPS location. Together, we’ll retrieve weather data from a public API and hide an API key in a PHP file for security. Finally, we’ll look at adding a manifest file and meta tags so that users can save the page to a device’s home screen and then launch it as a standalone app, including a custom icon for it.

Here is a screen shot of what we’re aiming for:

Step 1: What time is it?

See the Pen Wall Clock by Steven Estrella (@sgestrella) on CodePen.

The HTML for the clock has some placeholder text that we will eventually replace. All we really need at this moment is a centered container element and a couple of semantic elements for the date and time. The tag within the second element will be styled specially to display the running seconds and the meridian. The datetime attribute within the elements will be updated dynamically with JavaScript.

<main id="container" class="daymode">
  <time id="date" datetime="" class="clocktext">Someday, Anymonth 15, 20XX</time>
  <time id="time" datetime="" class="clocktext">12:00<span>:00 PM</span></time>
</main>

A little responsive design is key here. We want this to fit nicely on an iPhone 4s screen or any other small-ish smartphone in both portrait and landscape modes. We also want it to work well on a desktop web browser, of course. We can’t use any bleeding-edge CSS or JavaScript, however, because older devices like my iPhone 4s won’t understand it.

I wound up taking things up a notch by creating styles specific for the time of day and we’ll definitely get to that as well. We could even leverage a media query to darken the daytime style for Mac users who have dark mode turned on in the latest MacOS.

The tag with the running seconds and meridian will wrap nicely based on a width of 2em which is just large enough to accommodate two capital letters (i.e. AM and PM). The final CSS that’s needed is a media query to bump up font sizes when the clock is in landscape mode, or really any device with a viewport wider than 480px.

Here are the base styles we’re looking at, with the more decorative styles in the final app removed for brevity:

/* Base nighttime styles */
.nightmode {
  background-color: #121212;
  color: #fff;
}

/* Base daytime styles */
.daymode {
  background-color: #87ceeb;
  color: #333;
}

/* Target MacOS users who have Dark Mode enabled */
@media (prefers-color-scheme: dark) {
  .daymode {
    background-color: #003;
    color: #ffc;
  }
}

/* Used to wrap any lines of text  */
.clocktext {
  display: block;
  margin: 0;
  padding: 1px 0 0 0;
  text-align: center;
  white-space: nowrap;
  width: 100%;
}

#date {
  font-size: 1.3rem;
  padding-top: 15px;
}

#time {
  font-size: 5rem;
  margin: 1px 0 0 0;
}

#time span {
  display: inline-block;
  font-size: 1.5rem;
  line-height: 1.5;
  margin: 0 0 0 0.5em;
  padding: 0;
  text-align: left;
  vertical-align: baseline;
  white-space: normal;
  width: 2em;
}

@media (min-width: 480px){
  #date {font-size: 2rem;}
  #time {font-size: 8rem;}
  #time span {
    font-size: 2rem;
    line-height: 2;
  }
}

For the JavaScript, I chose ES5 because many features of ES6 don’t work on the mobile Safari browser in iOS 9.35, which is the final iOS that runs on the iPhone 4s. Fortunately, ES5 is more than up to the task and the app runs properly on newer devices as well.

We need variables for the current date and time (now), the element that will display the date (dd), the element that will display the time (td) and the names of the months and days. Once the page is loaded, an init function is called to update the time every second (1000 milliseconds). The getClockStrings() function updates the value in the now Date object and returns an object containing HTML strings for the date and time. Then the updateTime() function updates the HTML to show the time. One lesser-used feature here is the inclusion of the toISOString() method of the Date object which adds a machine-readable date string to the datetime attribute of the two elements.

Here’s what that boils dow to, using the JavaScript from the demo:

// NOTE: ES5 chosen instead of ES6 for compatibility with older mobile devices
var now, dd, td;
var months = ["January","February","March","April","May","June","July","August","September","October","November","December"];
var days = ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];

document.addEventListener("DOMContentLoaded", init, false);
function init() {
  dd = document.getElementById("date");
  td = document.getElementById("time");
  updateTime();
  setInterval(updateTime,1000);
}

function updateTime() {
  var clockdata = getClockStrings();
  dd.innerHTML = clockdata.datehtml;
  td.innerHTML = clockdata.timehtml;
  dd.dateTime = now.toISOString();
  td.dateTime = now.toISOString();
}

function getClockStrings() {
  now = new Date();
  var year = now.getFullYear();
  var month = months[now.getMonth()];
  var date = now.getDate();
  var day = days[now.getDay()];
  var hour = now.getHours();
  var minutes = now.getMinutes();
  var seconds = now.getSeconds();
  var meridian = hour < 12 ? "AM" : "PM";
  var clockhour = hour > 12 ? hour - 12 : hour;
  if (hour === 0) {clockhour = 12;}
  var clockminutes = minutes < 10 ? "0" + minutes : minutes;
  var clockseconds = seconds < 10 ? "0" + seconds : seconds;
  var datehtml = day + ", " + month + " " + date + ", " + year;
  var timehtml = clockhour + ":" + clockminutes + "<span>:" + clockseconds + " " + meridian + "</span>";
  return {"datehtml":datehtml,"timehtml":timehtml};
}

Step 2: Where are you?

See the Pen Clock with GPS by Steven Estrella (@sgestrella) on CodePen.

The Geolocation API is an easy way to get the user’s accurate location. We can do that when the page loads, but good manners and Chrome’s best practices audit dictate that we ask the user to initiate the location feature. So, we must add a button and a

to the HTML to display the GPS information we receive.

<button id="gpsbutton">Get GPS Location</button>
<div id="gps" class="clocktext infotext"></div>

These new items require their own styles — mine can be seen in the embedded Pen above. The important thing is to add the class selector rule for the infotext class as well as the two ID selector rules for the gpsbutton.

Finally, we’ll need to add the modified infotext class selector rule within the media query.

Again, the basic styles minus decorative styling for brevity:

/* The geolocation coordinates upon clicking GPS button */
.infotext {
  font-size: 1.3rem;
  line-height: 1.4;
  padding: 0 5px 0 5px;
  width: auto;
}

/* The button itself */
#gpsbutton {
  -webkit-appearance: none;
  -moz-appearance: none;
  display: block;
  margin: 0 auto;
  width: auto;
  cursor: pointer;
}

#gpsbutton:hover {
  /* Styles for the hover state */
}

@media (min-width: 480px){
  /* Add the rule below to the end of the media query */
  .infotext {font-size: 1.8rem;}
}

The JavaScript requires a few new variables for the latitude, longitude, GPS

, and GPS