To finish the Android competition application, I need to add the "updating functions". That is, send the information not updated to the Central Node (web server) and wait for a confirmation. If the confirmation arrives, information is in the Raspberry Pi3 whereas, when not confirmation is received, data should be resent in the next cycle.
This will require:
- HTTP_Client in the phone, to send the data as a HTTP_POST
- Communication service in the central node - PHP files able to receive the HTTP_POST message, extract the information and insert it into the database
Client and Server structure
We are focusing on the smart phone to central node communication. Data flow will start from the phone (client) to the central node (server).
1)User's node sends a HTTP_POST containing:
- Id - to be checked when received (to have some verification that the package was intended for the competition service)
- Distance tracked information for the user
The server check the id, and if it is the right one, it will extract the distance tracked information.
2)This information is saved into the database (created in post #5) to be access later on by the main GUI
3) If writing is successful, send response back to phone 4)
Data packets
The data packet structure is that of an HTTP_POST. The message, however, will contain a String with a JSON Array format: this way, I can have send several samples (several rows in the database), each of them with a key:value format. As a result, when the server receives the HTTP_POST, it will be easy to extract and identify each value.
(Images from JSON )
(*)NOTE - SECURITY . There is no type of protection against eavesdropping/ nor any security whatsoever. Nevertheless, traffic between user's node and central node should be, at least encrypted in the future.
Android App
Initial setup: Nexus 5 / Android / SmartCompetitionHome App v 1
I include a new java class to the project: ServerConnector.java
It makes use of the libraries:
- android-async-http: the HTTP client sending the information to the server, as an HTTP Post. It does not freeze the whole application while waiting fora response.
- gson: Creates a JSON structure with the information. It is an easier way of extracting the corresponding values when the package is received.
Sending data: ServerConnector.java
This class will be implementing an AsyncHttpResponseHandler (asyncHttpResponseHandler). This class defines two call back, onSuccess (when we obtain a successful response from the server) and onFailure (when we get some error). As stated before, this is an Asyncronous wait which will not freeze the app while the server response is traveling back.
It also holds fields with the server information: URL to send data to, JSONID etc.
Another important characteristic is the JSON String formatting of packages. To create this structure, this class implements convertToJSON method to obtain the desire JSON Array object from a List of Map<String, String>
public String convertToJSON( List<Map<String, String>> args){ String json = ""; Gson gson = new GsonBuilder().create(); //Use GSON to serialize Array List to JSON try { json = gson.toJson(args); }catch (Exception e){ System.out.println("Could not convert to JSON!: "+e); } return json;
So, the call to send a package to the server is as follows:
/** * sendToIITServer() * Function to send a JSON object to IIT server */ public void sendToCentralNode(String json, String url){ if (url != null && !url.equals("")) { System.out.println("Sending: " + json); System.out.println(url); //Set parameters RequestParams params = new RequestParams(); params.put(_JSON_ID, json); //Send http request httpClient.post(url, params, asyncHTTPClient); sending = true; }else{ System.out.println("Empty URL - Not sending"); }
When to send data?
The app should be able to send the data automatically (instead of having a SEND button). This can be done with a timer, every X seconds. However, I will use an even simpler solution since data recording does not have a high sample rate, nor do I need a lot of computation to process the track information. Data will be send every 5 new location detected. The code is found in CompetitionTrackActivity
if(num_locations == _LOCATIONS_TO_SEND){ num_locations = 0; List<Map<String, String>> notUpdated = myDB.getAllNotUpdatedValues(user_name, columnsTable, DatabaseManager.upDateColumn, DatabaseManager.updatedStatusNo); mServer.sendToCentralNode(mServer.convertToJSON(notUpdated), mServer.WRITE_URL);
(*)getAllNotUpdatedValues reads from the database all values that where not updated
Updating only not synchronized values
In order to maintain sync databases in the server and in the phone, we use an extra column to flag the state of each sample ("synchronized"). This way, when we send data, we only send samples with synchronized = 'no'. Afterwards, when the ACK arrives from the server, this synchronized is turn into a 'yes'
Central Node - Competition Service
Initial setup: Raspberry Pi 3 - Raspbian SO (Jessie) / SSH Enabled / Mosquitto MQTT Broker installed / MQTT Subsciber client / Console interface / Python GTK interface / MySQL Server / Apache2 web Server
A bit more of Re routing
In post #5 I showed how to do a port forwarding from the WiFi router to the Central node. I used port 80, to have web traffic redirected to the web server in the Raspberry Pi 3 (also, using port 80). However, for the competition service, I will be using another port. It can be done in two steps:
- Adding a new Port Forwarding rule in the router. Traffic entering thru PORT_COMPETITION will be redirected to the central node, PORT_RASPI_COMPETITION
- In the Raspberry Pi 3, traffic coming thru PORT_RASPI_COMPETITION has to be redirected to the PHP files providing the Competition Service. We do so by configuring the Apache server (we have it listening to Ports: 80, PORT_RASPI_COMPETITION):
- Modify its configuration files, in /etc/apache2/ to create a new VirtualHost for the PORT_RASPI_COMPETITION. It should point to the folder with the PHP Interface files.
- Restart apache2
PHP Interface - get new data and store it
The server will be receiving HTTP post request from the phone. It will make sure it is the intended data, then decode it an try to save it into the database.
Therefore, the proccess for any new request is:
1. Obtain the JSON Array Object
$json = $_POST["id_for_JSON"]; //Remove Slashes if (get_magic_quotes_gpc()){ $json = stripslashes($json); } //Decode JSON into an Array //Json structure: //{var data = ['{"table":"Name of table"}', '{"column1":"value1",..,"columnN": "value2"}'];} $data = json_decode($json); }
2. For each JSON Object, try to store it in the database
for ($i =0; $i < count($data); $i ++){ //Get keys of JSON for sensors values $res = $db->storeInTable($data[$i]->table_name, $data[$i]->date_time, $data[$i], $data[$i]->synchronized); //Build the array to send back $response[$i] = $res; }
(*)storeInTable is the function I designed to store each sample in the database. It requires table_name, date_time and synchronized fields to be passed separately. The other values can be stored automatically.
During the process, we also generate the $response, which will be encoded into another JSON packet. The difference will reside in the 'synchronized
' flag. If data was successfully updated in the database, 'synchronized' will be turn to 'yes' so that phone can then update its own local database.
Conclusion
We have our complete Competition application. Which means that, right now, the platform can:
- Record the distance walked into the phone app
- Send distance values to the central node
- Central node stores this distance values into MySQL database
To finish the platform, we will have to update our main GUI !
Top Comments