Web APIs and the IoT in Unity

Originally published at: http://www.sitepoint.com/web-apis-and-iot-in-unity/

For me, the Internet of Things is most exciting when you look at just how far reaching the capabilities are. There is so much technology out there, with new devices emerging all the time, that can benefit from connectivity to the web. Over the next few months at SitePoint, I’ll be looking at the various possibilities that the Internet of Things can bring, reviewing a different platform or device in each article. In the previous article, we looked at how to pull in data from the Jawbone Up.

This time around, we’ll be bringing IoT data into Unity, a widely used games engine that is used to build everything from iOS and Android games to console and Facebook games. It is also emerging as an engine that’ll be used on the Oculus Rift, Gear VR and more, so it’s a fun one to try pairing with the IoT. Imagine a game that adapts to real world conditions like weather and light, if it suddenly goes dark in your room, the game world suddenly goes dark too!

To start with, we’re going to connect up a Unity scene to a weather API, allowing us to use real-world weather data in our virtual world. Then we’ll connect up a Spark Core to use its light sensor data.

In this article, we’re assuming that you know all about setting up a scene in Unity, with a skybox, terrain and lighting. We’ll be building from a scene that has all of this ready and set up. My code samples will be in C# but it is possible to do the same sorts of things in UnityScript if you’d prefer.

Download the Demo Code

Working demo code for those who’d like to see this in action is available here.

Connecting Up to the Weather

Our first example of bringing in real world data will be setting up a skybox to change texture depending on the weather. Our sky is going to change to reflect the weather in our real world city! We’ll use OpenWeatherMap to pull in the latest weather data into Unity.

In order to control our scene’s Skybox, we’ll attach a script called IoTSkybox to an Empty Game Object called “SkyboxController”:

Our Skybox Code

In IoTSkybox.c, we include the following code:

using UnityEngine;
using System.Collections;

public class IoTSkybox : MonoBehaviour {
    public Material clearSky;
    public Material cloudySky;
    
    IEnumerator AdjustSkyToWeather() {
        while (true) {
            string weatherUrl = "http://api.openweathermap.org/data/2.5/weather?zip=2000,au";
            
            WWW weatherWWW = new WWW (weatherUrl);
            yield return weatherWWW;
            
            JSONObject tempData = new JSONObject (weatherWWW.text);
            
            JSONObject weatherDetails = tempData["weather"];
            string WeatherType = weatherDetails[0]["main"].str;
            
            if (WeatherType == "Clear") {
                RenderSettings.skybox = clearSky;
            } else if (WeatherType == "Clouds" || WeatherType == "Rain") {
                RenderSettings.skybox = cloudySky;
            }
            
            yield return new WaitForSeconds(60);
        }
    }
    
    void Start () {
        StartCoroutine (AdjustSkyToWeather());
    }
}

The JSONObject Class

One of the first things we’ll need to do for this code to work, is to add the JSONObject class. To do this, go to the Asset Store in Unity, search for “JSON Object” and you’ll see it available to import into your project:

Install it into your project and you’ll have access to the `JSONObject` class in your code. We should have everything we need for the code above to work, so it’s about time we cover what’s actually happening in that code.

The code explained

We register two public variables for us to define – clearSky and cloudySky.

public Material clearSky;
public Material cloudySky;

These are the two skybox materials we’ll be able to switch between depending on our weather data. We can then set which materials we want to use in the settings for our SkyboxController:

IoT Skybox Set Up

Next we’ll be using a Coroutine and IEnumerator. To start with, jump down to the Start() function:

void Start () {
    StartCoroutine (AdjustSkyToWeather());
}

Here we are starting our Coroutine. A Coroutine allows us to pause the function’s execution whenever we need to. We do that using a yield statement inside the Coroutine. We’ll be using it to wait for our web API response and to wait before regularly repeating our web call.

We define the IEnumerator function further up in our code, it starts with this line:

IEnumerator AdjustSkyToWeather()

Within it, we surround its contents with a while (true) statement, this will allow it to loop when the very last yield is returned.

The main bit where we’re performing our web call is the following group of code:

string weatherUrl = "http://api.openweathermap.org/data/2.5/weather?zip=2000,au";

WWW weatherWWW = new WWW (weatherUrl);
yield return weatherWWW;

That makes a web call to http://api.openweathermap.org/data/2.5/weather?zip=2000,au, which you can adjust to include whichever postcode and country code you’d like (I’ve got 2000 for Sydney and au for Australia).

We then set up a WWW object with that URL and then set up a yield which will return true once it has retrieved the contents at that address. Until then, it pauses this function.

This call returns JSON like so:

{
  "coord": {
	"lon": 151.2,
	"lat": -33.86
  },
  "sys": {
	"message": 0.0609,
	"country": "AU",
	"sunrise": 1430339337,
	"sunset": 1430378154
  },
  "weather": [
	{
	  "id": 801,
	  "main": "Clouds",
	  "description": "few clouds",
	  "icon": "02d"
	}
  ],
  "base": "stations",
  "main": {
	"temp": 291.487,
	"temp_min": 291.487,
	"temp_max": 291.487,
	"pressure": 1038.32,
	"sea_level": 1044.67,
	"grnd_level": 1038.32,
	"humidity": 89
  },
  "wind": {
	"speed": 3.26,
	"deg": 133.502
  },
  "clouds": {
	"all": 24
  },
  "dt": 1430354026,
  "id": 0,
  "name": "Millers Point",
  "cod": 200
}

That function returns a JSON string which we can read using weatherWWW.text. We create a JSONObject (remember the class we installed from the Unity Store?) from this text:

JSONObject tempData = new JSONObject (weatherWWW.text);

We then create one more JSONObject to store the JSON data that is nested within the weather key value. It returns an array, so we focus on the first element in the array and grab the string value of main, storing it in WeatherType:

JSONObject weatherDetails = tempData["weather"];
	string WeatherType = weatherDetails[0]["main"].str;

Then, if the weather type it returns is “Clear”, we set the skybox to use our clearSky material. If it is “Clouds” or “Rain”, then we use the cloudySky material:

if (WeatherType == "Clear") {
	RenderSettings.skybox = clearSky;
} else if (WeatherType == "Clouds" || WeatherType == "Rain") {
	RenderSettings.skybox = cloudySky;
}

Finally, we set our final yield to wait for 60 seconds, then return true. This will repeat our while statement every 60 seconds, checking the weather every minute.

yield return new WaitForSeconds(60);

Our results

If we run our Unity scene whilst there are clear skies in the town we’ve chosen (in my case Sydney), it looks like so:

If it is rainy or cloudy, it looks like so:

Continue reading this article on SitePoint

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.