Simple IoT application with Intel Galileo, Node Js and Android
This is a follow up to the Intel Galileo programming with node.js tutorial . We’ll be creating a sample iot application where we’d control a buzzer and a led with an Android app. It’s all based on what came on the previous tutorial: we’ll have an additional table on database that will hold data that syncs the mobile app to the Galileo Gen2 board. So if you are just starting with IoT or Intel Galileo check out the previous tutorials before starting here.
What we’ll build
-
A sample android app from wich you can add a threshold value for temperature. Once temperature sensor’s given value surpasses the threshold saved from mobile app, we’ll display it in maxTmpValue’s field ! This is about reading data from sensor to mobile app and vice versa. Then we’ll have a message to add on mobile app and display it on Grove lcd, as well as two switches to control a led and a Grove buzzer.
-
The needed webservices to save and consume captured data. And obviously the needed Intel Adrduino sketches.
Setting things up
- Node.js server + MySql database: In the previous tutorial I presented the steps to building a node.js server and setting up a MySql database for the purpose of this and the coming IoT tutorial(s). You can checkout the tutorial or just fork server’s code and update it to your proper configurations.
- Android project: create and sync an empty Android project where much of our work will be held.
Building webservices
We’ll need to code methods with the following calls on our server :
/updateThreshold: to be called from android app to change threshold’s value. /getThreshold: to be called from Arduino sketch to read threshold’s value.
/setMaxTmpValue: to be called from Arduino sketch to save the temperature sensor’s value once it surpasses the threshold value. /getMaxTmpValue: to be called from android app get the maximum temperature sensor’s value.
/updateMessage: to be called from android app to change threshold’s value. /getMessage: to be called from your sketch to change threshold’s value.
/updateSensorState: to be called from android app to change Led or Buzzer’s state value. /getSensorState: to be called from the sketch to read Led or Buzzer’s state value.
This is an example for the /updateSensorState call:
app.get('/updateSensorState', function (req, res) { var query = con.query("UPDATE states set status="+req.query.status+" WHERE sensor='"+ req.query.sensor+"'", function(err, rows) { if (err) console.log("Error Updating : %s ",err ); else res.json({Result:"updated"}) }); })
You would find all calls and the sql code for the database I used here. This is what we have in states table :
Consuming webservices from Android app
In this Android sample app we’ll have the single ui (screenshot above). We’ll use Volley Library to cosume the rest API we built : as long as there will be constant network calls we’ll be creating a static singleton instance of Volley’s RequestQueue that will last the lifetime of your app.
AppSingleton.java :
public class AppSingleton { private static AppSingleton mAppSingletonInstance; private RequestQueue mRequestQueue; private static Context mContext; private AppSingleton(Context context) { mContext = context; mRequestQueue = getRequestQueue(); } public static synchronized AppSingleton getInstance(Context context) { if (mAppSingletonInstance == null) { mAppSingletonInstance = new AppSingleton(context); } return mAppSingletonInstance; } public RequestQueue getRequestQueue() { if (mRequestQueue == null) { mRequestQueue = Volley.newRequestQueue(mContext.getApplicationContext()); } return mRequestQueue; } public void addToRequestQueue(Request req) { getRequestQueue().add(req); } public void cancelPendingRequests(Object tag) { if (mRequestQueue != null) { mRequestQueue.cancelAll(tag); } } }
Then in MainActivity.java w’ell use this class to perform out API calls depending on user’s interactions :
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ((Switch) findViewById(R.id.ledSwitch)).setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { if (isChecked) callMyApi("http://172.16.220.137:4300/updateSensor?status=1&sensor=led"); else callMyApi("http://172.16.220.137:4300/updateSensor?status=0&sensor=led"); } }); ((Switch) findViewById(R.id.buzzerSwitch)).setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { if (isChecked) callMyApi("http://172.16.220.137:4300/updateSensor?status=1&sensor=buzzer"); else callMyApi("http://172.16.220.137:4300/updateSensor?status=0&sensor=buzzer"); } }); } private void callMyApi(String url) { StringRequest strReq = new StringRequest(Request.Method.GET, url, new Response.Listener() { @Override public void onResponse(String response) { Log.d("Call Passed:", response.toString()); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { Log.e("ERROR", error.getMessage()); } }); AppSingleton.getInstance(getApplicationContext()).addToRequestQueue(strReq); }
You can find Android client project here. I provided a very basic simple for a web client as well here in case you want to test this on a web app.
Managing Galileo board and the sensors
In our Adruino IDE sketch we’ll be using WebClient library to make HTTP requests to our API. Then we treat the result returned depending on the sensor or senario we needed it for :
-
- Starting an Ethernet connection to Galileo Gen2 board
void connect_(){ while (!Serial) { ; } Serial.println("\n Connecting ..."); // Open serial communications and wait for port to open: system("ifdown eth0"); delay(500); system("ifup eth0"); // start the Ethernet connection: if (Ethernet.begin(mac) == 0) { Serial.println("Failed to configure Ethernet using DHCP"); // try to congifure using IP address instead of DHCP: Ethernet.begin(mac, ip); } // give the Ethernet shield a second to initialize: delay(1000); Serial.println("connecting to internet..."); Serial.println(Ethernet.localIP()); }
-
- Reading threshold value from database
// if you get a connection, report back via serial: if (client.connect(server, 4300)) { // Make a HTTP request: String req="GET /getThreshold"; client.println(req); client.println(); String resp=""; while(client.connected() && client.available()){ char c = client.read(); resp=resp+c; } resp = resp.substring(resp.lastIndexOf("\n")+1); Serial.println(resp); threshold=resp.toInt(); client.stop(); } else { // if you didn't get a connection to the server: Serial.println("connection failed"); }
-
- Reading temperature sensor’s value and saving it to db if it’s superior ti threshold
// Get the (raw) value of the temperature sensor. int val = analogRead(pinTemp); // Determine the current resistance of the thermistor based on the sensor value. float resistance = (float)(1023-val)*10000/val; // Calculate the temperature based on the resistance value. int temperature = 1/(log(resistance/10000)/B+1/298.15)-273.15; if(temperature>threshold) { // if you get a connection, report back via serial: if (client.connect(server, 4300)) { Serial.println("connected"); // Make a HTTP request: String req="GET /addTemp?value="; req+=temperature; req+="&capteur=Temp"; Serial.println(req); client.println(req); client.println(); client.stop(); } else { // if you didn't get a connection to the server: Serial.println("connection failed"); } }
-
- Reading message from db and displaying it on LCD
// reset the display: lcd.clear(); lcd.display(); lcd.setCursor(0, 0); if (client.connect(server, 4300)) { // Make a HTTP request: String req="GET /getMsg"; client.println(req); client.println(); String resp=""; while(client.connected() && client.available()){ char c = client.read(); resp=resp+c; } resp = resp.substring(resp.lastIndexOf("\n")+1); Serial.println("msg : "+resp); lcd.print(resp); client.stop(); } else { // if you didn't get a connection to the server: Serial.println("connection failed"); }
-
- Turning LED on/off depending on state value read from db
if (client.connect(server, 4300)) { // Make a HTTP request: String req="GET /getSensorState?sensor=led"; client.println(req); client.println(); String resp=""; while(client.connected() && client.available()){ char c = client.read(); resp=resp+c; } resp = resp.substring(resp.lastIndexOf("\n")+1); Serial.println("led : "+resp); led=resp.toInt(); client.stop(); } else { // if you didn't get a connection to the server: Serial.println("connection failed"); } if(led) digitalWrite(pinLed,HIGH); else digitalWrite(pinLed,LOW);
You can find source for all functionalities here.
After connecting your board and adding needed sensors, the result would be the following:
Wrapping things up
So as a wrap up : you need to build a rest api to exchange your data between the java android app and the C sketches on Arduino IDE and make them manage the same shared database. And you’ll have to create a simple android app that consumes your api to treat some database tables, that will be managed in your C sketches later on.
Recent Comments