Deploying the website consists of two things:
Once the website is hosted on Heroku, it'll be communicating with the cloud Database. Initially, there shouldn't be anything in the cloud database. Therefore, the webpage may not load. The way to work around this issue is to ensure that the database is loaded. Thus, the final component of hosting the website is: Loading Data onto Cloud Database.
3. Choose any cloud provider and region, it doesn’t matter for us. Just make sure it’s one in which a free tire is available.
4. Everything else remains default. Change the cluster name to any preferred name and Create Cluster. It may take a while for the cluster to get created.
1. To whitelist an IP Address, click on Connect and start by Adding a Different IP Address.
2. For IP Address, enter in 0.0.0.0/0. This represents a universal IP address binding.
3. Create a MongoDB user, with preferred Username and Password. Make sure to remember the username and password.
On the home page, start by clicking on Connect.
On the popup, Choose a connection method.
Click on Connect Your Application and the connection string will be displayed. Make sure to replace the db_user and <password> with the designated username and password created earlier.
1. Create an account for Heroku.
2. Feel free to use your UCSD email when registering. Put in UCSD for the company name.
3. On the Dashboard, click on the New at the top right corner and select Create new app.
4. Give it any App name that’s compatible and click on Create app.
5. Let’s set up the configuration variables. On the dashboard after creating an app, go to Settings and click on Reveal Config Vars.
6. For the KEY = DATABASE, for the VALUE we’ll be using the Connection String from MongoDB Atlas. Refer to the Locating Connecting String tutorial to find out where to get the connection. Don’t forget to replace the <password> field with the actual password for the Database. Once done, Add the Config Vars.
7. Download and install Heroku CLI to enable Heroku from the Terminal.
8. On the Terminal app, log into Heroku using the following command: heroku login
Follow the instruction to log into Heroku.
9. On the Termina app, in the project director, initialize a git repository using: git init
10, Add Heroku as a remote URL using: heroku git: remote -a <app name>
Replace <app name> with the name of the app that was given in the previous in step 4.
11. We don’t want to commit our node_modules folder and .env file to Heroku. To do so, open .gitignore on Sublime Text and add the two files.
12. We also wanna make sure that packet.json doesn’t contain Semantic-ui as one of the dependencies. If it’s there, make sure to remove it as a dependency. Make sure your packet.json looks something similar to the one below. Version number may vary. More importantly, verify that the only dependencies are: body-parser, dotenv, ejs, express, and mongoose. If there are more dependencies, make sure to remove them.
13. Commit the code to the repository and deploy it to Heroku using Git:
git add .git commit -m “initial commit”git push heroku master14. If everything is installed correctly, it should look something similar to the following:
If everything is done correctly, if we can open the web application by clicking on the Open app near the upper right corner of the dashboard.
However, as shown below, the page does not render! This is because Heroku is trying to load data from the MongoDB database, but the database has not data in it. Recall that homepage requires accessing the current color and settings from our database. Thus, the next step for us is to load the database with data. We'll be using Postman to load our data.
Use this link to download Postman. Once downloaded, open the add and configure it to match the image on the left Pay attention to these changes:
Click Send and wait for a response.
The response should look similar to the response we got from Heroku. That's because we're not done yet. We just loaded current color into the database. We still need to fill up our MongoDB database with initial settings from the homepage.
Next, configure it to match the image on the left Pay attention to these changes:
Click Send and wait for a response.
We should get a response of the HTML version of the homepage. Refresh the Heoku web application and it should now look familiar.
We're almost done now! The last step is to writ the Web API that the Raspberry Pi can use to communicate with our website. Refer to the following tutorial on how to do so:
Settings: GET
exports.getSettings = function(req, res) { db.Settings.findOne({}) .then( function(settings) { res.json(settings); }) .catch( function(err) { res.send(err); }); }Settings: PUT
exports.editSettings = function(req, res) { db.Settings.findOneAndUpdate({}, req.body, {'new': true, upsert: true}) .then( function(editedSettings) { res.json(editedSettings); }) .catch( function(err) { res.send(err); }); }Stats: GET
exports.getStats = function(req, res) { db.Stats.findOne({}) .then( function(stats) { res.json(stats); }) .catch( function(err) { res.send(err); }); }Stats: PUT
exports.editStats = function(req, res) { db.Stats.findOneAndUpdate({}, req.body, {'new': true, upsert: true}) .then( function(editedStats) { res.json(editedStats); }) .catch( function(err) { res.send(err); }); }helpers/settings.js
var db = require('../models'); exports.getSettings = function(req, res) { db.Settings.findOne({}) .then( function(settings) { res.json(settings); }) .catch( function(err) { res.send(err); }); } exports.editSettings = function(req, res) { db.Settings.findOneAndUpdate({}, req.body, {'new': true, upsert: true}) .then( function(editedSettings) { res.json(editedSettings); }) .catch( function(err) { res.send(err); }); }helpers/stats.js
var db = require('../models'); exports.getStats = function(req, res) { db.Stats.findOne({}) .then( function(stats) { res.json(stats); }) .catch( function(err) { res.send(err); }); } exports.editStats = function(req, res) { db.Stats.findOneAndUpdate({}, req.body, {'new': true, upsert: true}) .then( function(editedStats) { res.json(editedStats); }) .catch( function(err) { res.send(err); }); } exports.resetStats = function(req, res) { var blank = { 'avgTemperature': 0, 'avgHumidity': 0, 'avgBrightness': 0, 'timeInHot': 0, 'timeInCold': 0, 'timeInDry': 8, 'timeInHumid': 0, 'timeOn': 0, 'timeTotal': 0 } db.Stats.findOneAndUpdate({}, blank, {'new': true, upsert: true}) .then (function(wipedStats) { res.json(wipedStats); }) .catch( function(err) { res.send(erR);}); }helpers/data.js
var db = require('../models'); exports.getData = function(req, res) { db.Data.find() .then( function(data) { res.json(data); }) .catch( function(err) { res.send(err); }) } exports.createData = function(req, res) { db.Data.create(req.body) .then (function(newData) { res.json(newData); }) .catch ( function(err) { res.send(err); }); } exports.deleteData = function(req, res) { db.Data.remove({}) .then (function() { res.json({message: 'Data wiped' }); }) .catch (function(err) { res.send(err); }); } exports.getOneData = function(req, res) { db.Data.findById(req.params.id) .then (function(foundData) { res.json(foundData); }) .catch( function(err) { res.send(err); }); } exports.editData = function(req, res) { db.Data.findOneAndUpdate({ _id: req.params.id}, req.body, {'new': true, upsert: true}) .then (function(editedData) { res.json(editedData); }) .catch( function(err) { res.send(err); }); } exports.deleteOneData = function(req, res) { db.Data.remove( {_id: req.params.id}) .then( function() { res.json( {message: 'Succesfully deleted'}); }) .catch( function(err) { res.send(err); }); }routes/api.js
var express = require('express'), router = express.Router(), db = require('../models'), dataHelpers = require('../helpers/data'), statsHelpers = require('../helpers/stats'), settingsHelpers = require('../helpers/settings'); /***** * C - CREATE * R - READ * U - UPDATE * D - DELETE *****/ router.route('/data') .get(dataHelpers.getData) .post(dataHelpers.createData) .delete(dataHelpers.deleteData); router.route('/data/:id') .get(dataHelpers.getOneData) .put(dataHelpers.editData) .delete(dataHelpers.deleteOneData); router.route('/settings') .get(settingsHelpers.getSettings) .put(settingsHelpers.editSettings); router.route('/statistics') .get(statsHelpers.getStats) .put(statsHelpers.editStats) .delete(statsHelpers.resetStats); module.exports = router;Don't forget to push the API code to Heroku.
By now, the following should be completed: