How to create an office or studio status indicator and doorbell with NodeMCU Part #4
Welcome to part 4 of the series, we are going to be connecting the two devices we have built so far through EC2 and an express server using authenticated post requests. We are going to install express, point an event from the button click to our express server. We are going to need to create a https server so we will do that with freenom.
We are going to start where we left off inside our ec2 instance, so you can open that up with
ssh ubuntu
if you didn't make a ssh config file with the necessary information you can just do
ssh -i key.pem ubuntu@publicdns
Install Node with nvm
So once you've ssh into your instance, you can install nvm so we can then install node. Visit this github repo for nvm info.
Next run the following command
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.37.2/install.sh | bash
Then run
export NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm")" [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
and finally
. ~/.nvm/nvm.sh
nvm should now be ready to install node, just run to install node version 12
nvm install 12
Create a directory and install express
You can check if node installed with node -v
Next we want to create a directory
mkdir server && cd server
Then initialise a npm repo
npm init
Then install express
npm i --save-dev express
Then create a index file
sudo vim index.js
Then add the following code in the index file
const express = require('express')
const app = express()
app.get("/", (req,res) =>{
res.send("hey")
})
app.listen(3000, () => console.log("server running on port 300"));
Save that file and run and you will see the server is running
node index.js
Change security group on EC2 instance to include port 3000

Then go to loadbalancers -> create -> classic -> 80 to 3000

Assign the security group that is attached to your instance. Change the health check to visit just /
Create your load balancer. I t should take about 5 minutes to come into effect, once it's ready you can visit the DNS name and view our server in the browser.
Once status is 1of1 in service you can view the server in the browser

Now we are going to start connecting the devices together.
First up we want to install pm2, to do so go back to your ec2 instance console and run
npm i pm2 -g
and then run, in order to get our server back online and run in the background
pm2 start index.js
Next visit aws IoT and go to act -> destinations -> create

So we are going to have to do some configuration here, because we have a http
destination but it needs to be https
this is where freenom will come in handy.
So first got to https://freenom.com register a free domain and choose the following for your dns
Nameserver: COCO.NS.CLOUDFLARE.COM
Nameserver: CODY.NS.CLOUDFLARE.COM
as seen in the image below
Add cloudflare DNS (you will need a cloudflare account)

Go to cloudflare and add the new site, then choose the free plan.
Then add a cname in the dns Managment. We are using the aws dns address from before
like below
cname record for server

Now we need to a certificate in AWS in order for the domain to be secure so we can send a https request to the server.
So first go to aws -> certificate manager -> request a certificate
Then enter in your domain, choose DNS validation
Then add the cname it gives you in cloudflare seen below
Add this cname to cloudflare dns

Once the dns is saved AWS should eventually verify the dns record and your certificate should be issues, then we are just one step away from using that certificate on our load balancer.
Next visit EC2 -> loadbalancers in the aws console
Go to listeners then edit. Then click add HTTPS then click change SSL, then click choose a certificate, and choose the one you just created from the dropdown seen below
choose certificate

Change the cipher and choose the default and hit save.
Lastly add a https to anywhere in your security groups for the instance seen below
https security group

Your instance is now secure and you should be able to visit your domain with https in front of it. so visit aws IoT and go to act->destinations and paste it in.
First though we want to make a post url to visit, so open up the instance code server/index.js
Modify index.js
Require the following at the top of the file
var https = require("https")
var bodyParser = require("body-parser");
Then add the following post request api route
app.post("/doorbell", (req,res) =>{
console.log(req.body)
res.send("hellow world")
});
Next save the file, close it and install body-parser
npm i body-parser
then restart the instance with
pm2 restart index.js
then visit aws and hit create destination to
https://yourdomain.ml/doorbell
Once you are done that open up pm2 logs with
pm2 logs
and then you should see the confirmationToken and go back to aws with that token and copy and paste it under actions -> confirm and enable as seen below
confirmation token

Then you want to create a rule, so visit aws console IoT -> act -> rules give it a name a use this as your query
SELECT * from "devices/#"
Click add action next, and choose send a message to a downstream HTTPS endpoint as seen below
add action to https destination, and choose https://yourdomain.ml/doorbell

Next hit add action, and then create rule. So now anytime the button is pressed it's going to send a request up to the server. Next if you visit your ec2 instance and are in your pm2 logs, when you click the button on the status indicator with two leds, you should get a message in your console.
Next we are going to take the request and send a message to the shadow of the other device and turn it's led on, and then off after three seconds.
Next we are adding the code to turn the led on after button press
Open up server/index.js
and add the following code, and make sure you select the board you want to change the led on in the path:
//...
var aws4 = requrie("aws4")
app.use(bodyParser.json())
function request(opts) {
return new Promise(function(resolve, reject){
https
.request(opts, function(res){
res.pipe(process.stdout)
res.setEncoding("utf8");
let body = "";
res.on("data", (chunk) => (body += chunk));
res.on("end", () => {
let json = JSON.parse(body);
resolve(json.state)
});
}).end(opts.body || "")
});
}
function lightbulb(status){
var load = JSON.stringify({
state:{
desired:{
on: status,
},
},
})
request(
aws4.sign(
{
hostname: "a3w047vc4j3fpy-ats.iot.us-east-1.amazonaws.com",
service: "iotdata",
region: "us-east-1",
method: "POST",
path: "/things/esp8266_112222/shadow",
headers: {
"Content-Type": "application/json0",
},
body: load,
},
{
secretAccessKey: "yoursecret",
accessKeyId: "yourid",
}
)
)
}
//...
And then add the following in the post route
app.post("/doorbell", (req,res) =>{
console.log(req.body)
lightbulb(true)
setTimeout(function(){ lightbulb(false)}, 3000);
res.send("hellow world")
});
save and quit, install aws4 and restart the server with
npm i aws4
pm2 restart index.js
You will notice now when you press the button on the first device the red led will turn on on the second device for three seconds
Now we are going to do the reverse with a answer post request
Go to server/index.js
in your instance and write the following new code
function lightbulbAnswer(status){
var load = JSON.stringify({
state:{
desired:{
on: status,
},
},
})
request(
aws4.sign(
{
hostname: "a3w047vc4j3fpy-ats.iot.us-east-1.amazonaws.com",
service: "iotdata",
region: "us-east-1",
method: "POST",
path: "/things/esp8266_7F8471/shadow",
headers: {
"Content-Type": "application/json0",
},
body: load,
},
{
secretAccessKey: "yoursecret",
accessKeyId: "yourid",
}
)
)
}
app.post("/answer", (req,res) =>{
console.log(req.body);
lightbulbAnswer("free");
res.send("hello world");
});
Next run through the same create destination in aws IoT destinations as your did for the first one except this time use https://yourdomain.ml/answer
and enter it's confirmation token after you have restarted the pm2 server.
Then create a rule for it, but this time make your query different it should be as follow, and create an action to this new destination
SELECT * from "answer1/#"
Then we need to make one last modification in the secondary devices code, open up it's init.js file and change the following line to say answer1 instead of devices, build, flash, connect to wifi and then connect to aws.
// AWS is handled as plain MQTT since it allows arbitrary topics.
if (AWS.isConnected() || (MQTT.isConnected() && sendMQTT)) {
let topic = "answer1/" + Cfg.get("device.id") + "/events";
print("== Publishing to " + topic + ":", message);
MQTT.pub(topic, message, 0 /* QoS */);
} else if (sendMQTT) {
print("== Not connected!");
}
Once all is said and done you should be able to git the button on the secondary device and change the led to green on the status indicator, showing you are free.
Congrats you made it ;)