Node.js + AWS: Change Lights Color based on the Weather

Raphaël Léger
6 min readDec 23, 2019

Good evening ladies and gents, it is going to be SOOO SUNNY tomorrow.

When you get to that tomorrow:

Guys, guys, guys, where the sun at…?

Problem

Weather news are based on probabilities and those probabilities seem to get accurate only on the day itself.

But who has the time and energy to manually check the weather on the day itself, probably on the morning before leaving to work?

Well, certainly not me!

Long story short

tl;dr: with mighty programming skills, I made a bunch of lights automatically show me some weather forecast every day 💡

Let there be light

So… first step: I bought a LED strip, a band made of tiny lights that can change color.

I like the red a lot, it gives a nice cozy atmosphere.

Let there be WIFI

To talk to the LED strip through a computer program, I got myself a WIFI controller and connected it to the strip.

The WIFI controller gave my LED strip an IP address within my local network.

Here comes the code

I decided to use the JavaScript runtime Node.js as it comes with tons of practical libraries, performs async operations easily, and is well supported by cloud providers.

Getting weather forecast

So I created an account on the OpenWeatherMap API, an online service to retrieve weather forecasts.

Then using a Node.js wrapper, I wrote two functions:

  • One to retrieve the list of weather forecasts for Paris.
  • One to tell whether is is going to be rainy today in Paris based on the forecasts: if at least one forecast says it is going to rain, consider it rains.
import weather from 'openweather-apis'const getTodayWeatherForecast = () => {
return new Promise((resolve, reject) => {
weather.setLang('en')
weather.setCity('Paris')
weather.setUnits('metric')
weather.setAPPID(process.env.OPEN_WEATHER_MAP_API_KEY)
weather.getWeatherForecast(function(_, forecast) {
if (forecast.cod !== "200") {
reject(`Error`)
} else {
resolve(forecast.list)
}
})
})
}
export const todayIsGoingToBeRainy = async () => {
const forecast = await getTodayWeatherForecast()
return forecast.some((el) => {
return el.weather[0].main === "Rain"
}
}

Establishing contact with the light strip

I then used a Node.js utility to communicate with my WIFI controller and wrote an other function. Its goal: establishing a connection to my LED strip and returning a controller object that I could then use to send instructions to the strip such as turning it on, turning it off, changing its color.

import { Control } from 'magic-home'export const getLedStrip = async () => {
const ledStripIp = process.env.LED_STRIP_IP_ADDRESS
return new Control(ledStripIp, {
ack: {
color: false
}
})
}

The program: checking weather and setting LED strip color

After having defined all the functions I needed, I assembled them into this simple program:

export const checkWeatherAndSetLedStripColor = async () => {
const light = await getLedStrip()
await light.turnOn()
await light.setColor(0, 0, 0) // white
const rainingToday = await todayIsGoingToBeRainy() if (rainingToday) {
return light.setColor(0, 0, 255) // blue
} else {
return light.setColor(255, 220, 0) // yellow
}
}

Step-by-step, what this code does is it establishes a connection with the LED strip. Then, it then checks whether it is going to rain today and if so orders the LED strip to become blue. If no rain is forecasted, it orders the LED strip to become yellow.

Executing the program

checkWeatherAndSetLedStripColor()
Yellow light: today is going to be sunny!

Running everything every morning

I wanted the program to run automatically every morning.

Hey, wait. Isn’t that a very good occasion of going serverless and using the cloud so that I do not even need to turn on a computer in my home at all?

Damn, if only my LED strip itself was in the cloud…

Exposing the LED strip to the world

Make the LED strip IP static

Before exposing my LED strip to the world, I needed to make sure that its IP address was going to stay the same forever.

Internet Service Providers (ISP) provide a web interface enabling anyone to administrate their local network. Somewhere within this interface, a Device Management tool made it possible to select the LED strip device and assign it a static IP address.

Allow internet to access the LED strip

Using a Port Forwarding tool available on the ISP administration interface, I created a new forwarding rule.

In that rule, I decided that the external port 5555 of my internet box would be redirected to my WIFI controller, meaning anyone out there on the internet sending a message to my internet box on the port 5555 was actually going to be talking directly to my LED strip.

And guess what, that anyone was going to be me.

Deploying everything in the cloud

Using my public IP address

Before deploying anything online in the cloud, I had to replace the local LED strip IP address known by the program until then with my public IP address. This enabled the program to be run from anywhere and not just from within my local network.

Configuring AWS

Prior to using Amazon Web Services (AWS), there are two things to do:

  1. create an AWS account
  2. install and configure the AWS command line interface

Choosing how to deploy on AWS

There are many ways to deploy services on AWS - in the cloud.

For this project, I chose to go with a simple framework called Serverless Framework. It is based on a kind of “infrastructure as code” paradigm and it alleviates the definition of some stuff we don’t really care about for a quick proof-of-concept project.

Configuring Serverless Framework

Right after installation, I added some configuration into a serverless.yml file:

service:
name: led-strip-weather
provider:
name: aws
runtime: nodejs12.x
region: eu-west-1
timeout: 30
functions:
checkWeatherAndSetLedStripColor:
handler: handler.checkWeatherAndSetLedStripColor
events:
- schedule: cron(20 7 ? * MON-FRI *)
environment:
LED_STRIP_IP_ADDRESS: ${self:custom.environment.LED_STRIP_IP_ADDRESS}
OPEN_WEATHER_MAP_API_KEY: ${self:custom.environment.OPEN_WEATHER_MAP_API_KEY}
turnLedStripOff:
handler: handler.turnLedStripOff
events:
- schedule: cron(0 8 ? * MON-FRI *)
environment:
LED_STRIP_IP_ADDRESS: ${self:custom.environment.LED_STRIP_IP_ADDRESS}
custom:
environment: ${file(.env)}

The file first declares that we want AWS as our cloud provider and that the code will run through Node.js.

Then it states that our services are going to be two functions:

  • One that checks the weather and sets the LED strip color accordingly.
  • One that turns the LED strip off.

I provided earlier the code of the first function. Here is the code of second one, much plain simple:

export const turnLedStripOff = async () => {
const light = await getLedStrip()
return light.turnOff()
}

In addition to the code, the functions are also given environment variables and are binded with events so that they get run automatically at certain points in time.

Here I decided that the first function would run at 7.20 am once every weekday and that the second function will run at 8.00 am every weekday.

Deploying

With the configuration properly set up, deploying the service on AWS was done by executing the following command:

serverless deploy

The deployment actually created the two lambda functions on AWS and assigned them the defined schedule events. The final architecture is as follow:

The led-strip-weather project’s architecture

Final result

Every morning I see blue lights, I take a coat with me.
Every morning I see yellow lights, I don’t.

Blue light: rainy day :(
Yellow light: sunny day :)

Thanks for reading along!

--

--