Saturday, February 1, 2014

Building a Wireless Temperature Sensor Network Part 6

Welcome back for part 6, the final post in the building a wireless temperature sensor network saga. In part 5 we added internet monitoring and data logging capability to our temperature sensor network using the Arduino Yun. In this post we will discuss how we can access our wireless sensor network from behind a router firewall, giving us the capability to access it from across the street to across the globe. We will also add the ability to monitor our wireless temperature sensor network from an iOS device such as an iPhone or iPad, which gives us even further flexibility to access our temperature sensor network.

By using the ubiquitous TCP / IP protocol to communicate out the temperature data we have the ability to monitor it from almost anywhere. The roadblock we run into is the firewall in the WiFi router that the Arduino Yun is connected to restricts us to only connecting to the sensor network from within the router's local WiFi / Ethernet network. A basic home WiFi router's default configuration assumes all the devices connected to its local network are clients and will be the ones to initiate communication with a device outside the local network. Because of that any device outside of router's local network that tries to initiate communication with a device inside the router's local network must have malicious intensions. The problem is the Arduino Yun is configured as a server, but the router does not know that. To change this you would need to go into your routers settings and poke a hole in the firewall. The router's settings can typically be accessed through its web page. Refer to your router's user manual for the address to access the web page. Once you get access to your router's settings you have two options for poking a hole in the firewall to access the Yun, Port Forwarding and DMZ. Port Forwarding, which is the safer of the two but is a little more complex to setup, requires you know the TCP / IP communication port that you plan to communicate through (we used 6666 in our Arduino code) and the IP address of the Yun. DMZ just requires you to know the IP address of the Yun. With DMZ set for a specific device or IP address on its local network the router then sends any incoming communication requests from outside the firewall to the specified IP address, regardless of the port. Before moving on there are two other things you should be aware of when trying to connect to your temperature sensor network over the internet:
  1. When outside of your router's firewall you need to use the IP address of the router to connect to the Yun, not the local IP address of the Yun that the router assigns to it. To get the IP address of your router just search "My IP Address" on Google and it will show up in the results. 
  2. Your router will not assign a permanent IP address to the Yun, it will change once and awhile with no warning. To avoid this hassle go into your router settings and assign it a static IP address (an address that will not change).
I know that was a lot of information to swallow if you are not familiar with the Ethernet networks, but if you get stuck just search on the internet. There is plenty of information out there on the topics we just covered. 

To connect to and fetch temperature data from our wireless sensor network from an iOS device we will make some slight changes to our Arduino Yun code presented in the last post (part 5). Instead of posting the whole sketch again, you will just find the two sections of the code where changes were.

//The global strings for storing latest temperature reading are initialized with the string "Empty"
String sen1Temp = "Empty"; //stores temperature value for XBee with sensor 1
String sen2Temp = "Empty"; //stores temperature value for XBee with sensor 2
String sen3Temp = "Empty"; //stores temperature value from Yun with sensor 3


/*The portion of the code where we accept the client connection and send the data has been simplified since now we are only sending one string of data, instead of three separate strings. We will let the iOS code parse the string into three separate values*/
YunClient client = server.accept(); //accept any client trying to connect
  if(client.connected()){ //If we are connected to a client send identity and temperature data
    String temp = sen1Temp + "," + sen2Temp + "," + sen3Temp + "\n";
    
    client.write((uint8_t*)&temp[0], temp.length()); //send sensor 1 temp or low battery warning
    client.stop(); //disconnect from client
  }

/*Lastly this function was changed to simplify the three global strings that hold the data that we will send out*/
void setAndLogSensorValue(int sen, float val, int temp) {
  String dataString = getTimeStamp() + " "; //get time info and append space to the end
  
  if (sen == 1) { //sensor 1
    if (temp == 1) {
      sen1Temp = String(val); //store latest temp value in global string
      dataString += "Sensor 1 temperature: " + sen1Temp + "\n"; //build datalog string
     writeToFile(dataString); //write temp value to file 
    }
    else { sen1Temp = "Low Battery"; }
  }
  else if (sen == 2) { //sensor 2
    if (temp == 1) {
      sen2Temp = String(val); //store latest temp value in global string
      dataString += "Sensor 2 temperature: " + sen2Temp + "\n"; //build datalog string
      writeToFile(dataString); //write temp value to file
    }
    else { sen2Temp = "Low Battery";}
  }
  else {
      sen3Temp = String(val); //store latest temp value in global string
      dataString += "Sensor 3 temperature: " + sen3Temp+ "\n"; //build datalog string
      writeToFile(dataString); //write temp value to file
  }
}

To create apps for the iOS you need XCode, which is Apple's software development environment and it only works on Macs. XCode uses the Objective C programming language which is based off of C but its syntax is vastly different (in my opinion). XCode is free to download and you can test your iOS code on an iPhone or iPad software simulator that runs on your Mac. To actually put your code on a physical iPhone or iPad or to post an app on the App Store you need to pay for a $99 per year subscription. For this project a simple iOS app called "SensorMonitor" was put together with a basic user interface for example purposes. Before we discuss the code, below is a screen grab of the SensorMonitor iOS app that connects to the wireless sensor network and fetches the temperature data. The IP address of the wireless network is typed into the text box at the top of the app. When the "Get Temperature Data" button is pushed the app connects to the sensor network, receives the temperature data, and prints the temperature next to the corresponding sensor label. Below on the left is a screen shot of the SensorMonitor app before the button was pushed to retrieve the temperature data. On the right is a screen shot of the app after the button was pushed and the temperature data is displayed next to the corresponding sensor label.  


Even for a simple iOS app like SensorMonitor there is too much code and different files to display and cover in this post. What is shown below is the "IBAction" function from the app's code. The IBAction function is called when the "Get Temperature Data" button is pressed, the function name is "goConnect." The goConnect function is commented to explain what is happening at each line. 

//This function is called when the "Get Temperature Data" button on the user interface is pressed
-(IBAction)goConnect { //connect button action method
    NSError *hError; //declare variable to store error info
    NSString *tempVal; //string to hold temperature data from Yun
    
    if (![io openWithAddress:self.ipTextField.text port:6666 error:&hError]) { //connect to Arduino Yun on port 6666
        //Connection failed print the error to the message label
        self.message.text = [[NSString alloc] initWithString:[hError localizedDescription]]; //display error if connection failed
        [io closeWithError:&hError]; //if already connected and button was pressed, disconnect from Yun
    }
    else { //the connection was a success
        //get sensor 1 temperature data
        if(![io scan:&tempVal trimNewLine:YES error:&hError]) { //read the first sensor value
            self.message.text = [[NSString alloc] initWithString:[hError localizedDescription]]; //if error occurred display error details
            self.sen1.text = @"Read Failed"; //temp data read failed so tell user
        }
        else {
            self.sen1.text = tempVal;
            NSArray *tempData = [tempVal componentsSeparatedByString:@","];
            //self.sen2.text = [tempData objectAtIndex:1];
            self.sen1.text = [@"Sensor 1: " stringByAppendingString:[tempData objectAtIndex:0]]; //Add the sensor 1 temperature data to the Sensor 1 label
            self.sen2.text = [@"Sensor 2: " stringByAppendingString:[tempData objectAtIndex:1]]; //set sensor 2 label to the temperature value just read
            self.sen3.text = [@"Sensor 3: " stringByAppendingString:[tempData objectAtIndex:2]]; //set sensor 3 label to the temperature value just read
    
            self.message.text = @" "; //There were no errors so leave message blank
        }
        [io closeWithError:&hError]; //if already connected and button was pressed, disconnect from Yun
    }
}

If you are interested in accessing the SensorConnect app's code in full just email me at forcetronics@gmail.com and I will send it to you. The value of the SensorConnect app to someone who wants to monitor a sensor network with an iOS device is the code that does the communication with the Yun using TCP / IP protocol. Myself and a colleague of mine created an Objective C API made up of three classes to communicate over Ethernet. In the above function, the "io" object is a handle to the API for connection and communication with the Arduino Yun.

In this 6 part project we went over how to build your own wireless temperature sensor network that included features such as:
  • Temperature data communicated using Zigbee protocol
  • Battery powered sensors
  • Time stamped temperature data logging
  • Monitoring over the internet using an iOS device
This project was meant to serve as a foundation or starting point for you to build your own custom temperature sensor or any type of sensor network. If you found any of the information in this project useful please click on one of the ads in this blog to help fund future projects. If you have any comments or questions related to this post or this project use the Comment section below or send me an email at forcetronics@gmail.com. See you back soon for the next project!