Table of Contents
Background
One of many requirements to graduate from university and earn my Bachelor’s of Science in Computer Science degree from Western Michigan University included the successful completion of CS 4900 and CS 4910 - collectively called “Senior Design” - and the year-long planning, implementation and presentation of the course’s capstone project.
Entering CS 4900 (the first half) in Fall 2015, I had originally grouped up with two other students to work on a custom project. In Senior Design, custom projects require written submission and approval by the professor - otherwise, students are to select one of several existing projects to continue from previous years. The original idea, headed by one of the other two members in my group, was to create a Ruby on Rails community-based resource and asset sharing application. Essentially, users would be able to coordinate with other users from the same community and share information and personal assets upon electronic request.
At the time, this idea seemed favorable to the existing rehashed projects available. We submitted our idea in writing to the professor and were approved to begin the planning phase of our project. Progress was slow at first, but slowly picked up as time flowed into late October and early November 2015.
Unfortunately, disaster soon struck as our head member was involved in an extremely horrific car accident, forcing him to postpone his graduation and remain in the hospital for days before being allowed to return home. He ultimately decided not to continue coursework for the semester, leaving the third member and I with a decision - do we continue to work on the Ruby on Rails project, or do we start from scratch? As fate would have it, a third option presented itself to us.
Having already begun my internship for Consumers Energy in March 2015, I knew of another Senior Design project started in Spring 2015 and scheduled to be finished in Fall 2015 by another team for the company at which I was employed. This team had not implemented all the features it had intended to implement by the time they were required to present their project (which I attended), and because of that and my connection to the same company, it was possible for my team to continue working on it as a “version 2” of the project.
We submitted this idea to the professor, who was skeptical at first, but due to the extraordinary circumstances and unexpected events did eventually approve of the idea. We now found ourselves short on time - we were just finishing the first half of the course, but just beginning work on the project which was supposed to be a year-long endeavor.
The project was a hybrid-mobile application, a newer kind of framework allowing the programmer to develop cross-platform mobile applications written in common web technologies (i.e. HTML, CSS, JavaScript), differing from the traditional native app written in Java for Android or Swift/Objective-C for iOS.
Objectively, the application was designed to enhance and improve the user’s experience in reporting streetlight and power outages in the local area, allowing faster response times for crews to be dispatched and make their repairs.
While many of the planned features were available in “version 1” of the app, several were not due to time constraints by the first group. For version 2, my team would implement these features along with many of our own. With the clock ticking, we got to work.
Implementation
In the version 1 release, the application supported streetlight and power outage reporting but had not matured enough to support additional desired functionality. As such, several new features were to be added for our iteration of the project. These included:
- Listing alternative energy posts
- First-use tutorial page(s)
- Improved production scalability
- HTTPS via SSL certificate
- IPTables firewall policy
- Various UI enhancements
- Push notifications
- Android usability
My partner and I figured these could all be accomplished, and we were both familiar with the programming languages used for both the backend (Python Flask) and more significantly, the frontend (HTML, CSS, JavaScript) via the AngularJS and Ionic frameworks. Essentially, the application operated in these two segments - clients would submit HTTP requests such as registration and outage information in the mobile app to a Python Flask webserver, where data would be stored in a SQL database, and replies formatted as JSON responses would be sent back to the client as needed to facilitate bidirectional communication.
The vast majority of our actual programming work would therefore be implemented on the frontend, given the above desired features. The backend work to be performed was mostly administrative and security-focused - not features that the end user interacts with directly.
Alternative Energy Posts
From a publicly available online database of alternative energy posts, we were able to quickly obtain geolocation data of biodiesal, compressed natural gas, E85 Ethanol, electric, Hydrogen, and Propane sources to display on Google Maps markers. Since the frontend logic was written predominantly in JavaScript, adding markers was a fairly simple task to complete:
$scope.mapCreated = function(map) {
$scope.map = map;
setTimeout(function() {
// Biodiesal
$scope.addNewMarker(new google.maps.LatLng(46.668324,-85.998166), 1);
$scope.addNewMarker(new google.maps.LatLng(42.2972618,-83.7015238), 1);
$scope.addNewMarker(new google.maps.LatLng(43.0059745,-84.3760119), 1);
// Compressed Natural Gas
$scope.addNewMarker(new google.maps.LatLng(42.9775004,-82.4484513), 2);
$scope.addNewMarker(new google.maps.LatLng(42.3763095,-83.2173177), 2);
$scope.addNewMarker(new google.maps.LatLng(42.2395629,-83.7658112), 2);
// E85 Ethanol
$scope.addNewMarker(new google.maps.LatLng(42.7704045,-84.4194015), 3);
$scope.addNewMarker(new google.maps.LatLng(42.8125767,-86.0784455), 3);
$scope.addNewMarker(new google.maps.LatLng(42.170847,-83.188294), 3);
// ...
}, 3000);
}
First-Use Tutorial
To improve end user experience, we also added a first-use tutorial explaining how the application functioned. This was completed in a separate HTML file called help.html
:
<ion-modal-view>
<ion-header-bar class="bar-positive">
<h1 class="title">Help</h1>
<div class="buttons">
<button class="button button-clear" ng-click="closeHelp()">Close</button>
</div>
</ion-header-bar>
<ion-content scroll="true">
<img src="img/ce.png" alt="" style="width:100%;height:20%;repeat:no-repeat;padding:10px;">
<div class="help_text" style="padding:15px;">
<p>1. Welcome! Thanks for trying out this new app!</p>
<p>2. The following information serves as a reference on how this application works, how to navigate this application, how to report outages, how to register, and so on.</p>
<div class="help_text_2" style="padding-left:15px;">
<p><i class="icon ion-ios-arrow-thin-right" id="iconSpace"></i> Use the <i class="icon ion-android-menu"></i> icon to view the side menu. All the other uses of this application are listed here.</p>
<p><i class="icon ion-ios-home-outline" id="iconSpace"></i> Under the side menu, tap "Home" to view the home page and RSS feeds.</p>
<p><i class="icon ion-log-in" id="iconSpace"></i> Under the side menu, tap "Login" to log into the application with the user account you created with the "Register" page.</p>
<p><i class="icon ion-log-in" id="iconSpace"></i> Under the side menu, tap "Register" to create your own user account. This account will be used to validate outage reporting.</p>
<p><i class="icon ion-ios-location-outline" id="iconSpace"></i> Under the side menu, tap "Power Outage Map" to report power outages.</p>
<p><i class="icon ion-ios-lightbulb-outline" id="iconSpace"></i> Under the side menu, tap "Streetlight Outage Map" to report streetlight outages.</p>
<div class="help_text_3" style="padding-left:15px;">
<p>1. Optionally find your current location by tapping "GPS".</p>
<p>2. Add pins to the map by tapping the "<i class="icon ion-pin"></i> Pin" button.</p>
<p>3. Remove pins from the map by tapping the "<i class="icon ion-ios-trash-outline"></i> Pin" button.</p>
<p>4. Tap "Send" to report the streetlight outages at your specified pin locations.</p>
<p>5. Tap "Send" again after confirming your locations are correct.</p>
</div>
<p><i class="icon ion-loop" id="iconSpace"></i> Under the side menu, tap "Alternative Energy Posts" to view alternative energy locations around the state.</p>
<p><i class="icon ion-wand" id="iconSpace"></i> Under the side menu, tap "Help" to view this page.</p>
</div>
</div>
</ion-content>
</ion-modal-view>
Improved Scalability
For version 1, the team used the same setup in development and testing as they did in production. In an ideal topology, development, testing and production are separated to allow staging and quality assurance (QA) before changes are implemented and approved for production. In order to accommodate this topology and improve scalability, we added a dedicated machine to our process flow and designated it to be our new production server.
We were also able to run scalability benchmarks for stress-testing against our new production Apache webserver by utilizing ApacheBenchmark:
HTTPS
Being a stickler for security, I made it a personal requirement to myself to force the application to use HTTPS rather than the insecure HTTP especially since registration data was being transmitted to the Flask server. This meant that if someone was listening in on the connections being made to our server, an attacker could harvest credentials via man-in-the-middle eavesdropping. Therefore, I implemented a free SSL certificate issued by the Let’s Encrypt project to encrypt user traffic and protect against these sorts of vulnerabilities.
IPTables Firewall
It was unclear if a proper firewall had been implemented in the first version of the application. IPTables, the most common firewall used on Linux server distributions, was immediately added to both our testing and production servers to ensure that only my partner and I had access to SSH, and to restrict connections to our database. I normally write a simple Bash script to handle firewall rules in Linux, which may have looked something like this:
iptables -P INPUT ACCEPT
iptables -P FORWARD ACCEPT
iptables -P OUTPUT ACCEPT
iptables -F
iptables -X
iptables -I INPUT 1 -i lo -j ACCEPT
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -p tcp -m multiport --dports 80,443 -j ACCEPT
iptables -A INPUT -s 127.0.0.1 -j ACCEPT
iptables -A INPUT -s <ip> -p tcp -m tcp --dport 22 -j ACCEPT
iptables -A INPUT -j DROP
iptables-save
UI Enhancements
Given that the hybrid-app was written in HTML, CSS, and JavaScript, we had direct access to modify the user interface design, styling and layout as we saw fit. We found ourselves mostly editing the CSS rules to improve end user experience. For example, to edit the energy calculator, we simply needed to modify the .calculator
CSS rules:
.calculator {
background-attachment: fixed;
background-image: url('../img/cloud-bg.png');
background-position: center;
background-repeat: no-repeat;
background-size: cover;
height: 400px;
width: 560px;
}
Push Notifications
Push notifications allow the company or application owner to send notifications to the user’s mobile device, where they may or may not show up on the home (or lock) screen of the phone. Naturally, this would prove useful for an energy provider wishing to communicate with its customers about known outages or even emergency situations.
Due to this reasoning, my partner and I added the foundation for push notifications in the application but were unable to request testing on behalf of the company. We were only able to test push notifications in our non-prod environments, where they worked as intended.
Android
Supporting Android required little to no effort on our part at all. One of the main selling points of hybrid-apps is cross-platform availability due to the Cordova container housing the HTML, CSS, and JavaScript inside the application. Since version 1 performed usability testing solely on Apple devices, as this was all that they had available to them, we were able to test both since I carried a Samsung Galaxy S4 and my partner carried an iPhone. Once we were satisfied resolving the UI discrepancies between the two mobile platforms, Android was supported.
Results
My partner and I received lots of praise and full credit (A) for our work on the application after completing our final presentation and project submission. Despite the initial pullbacks and being behind schedule, the long hours we put in together to exceed our professor’s expectations paid off at the end of my college career. I could not have known how well this experience would prepare me for years to come in the real world.
Presentation
The full presentation slides document is available for download in .pdf
format.
Demo
The following video demonstrates some of the application’s basic functionality, such as reporting streetlight outages and searching for alternative energy posts around the state of Michigan. It also details the registration process and an energy equivalency calculator used to measure the relative difference in cost between the U.S. dollar and various forms of energy production compared against environmental impact-related metrics.