JavaScript with Hardware [Part Two]: Using Modern JavaScript

JavaScript with Hardware [Part Two]: Using Modern JavaScript © MIT

Part Two of a series covering JavaScript with Hardware! Iain covers the use of JavaScript devtools and using modern JavaScript features.

  • 1,599 views
  • 1 comment
  • 12 respects

Components and supplies

Apps and online services

About this project

Hope you enjoyed the first few posts on JavaScript and Hardware! If you've missed the previous parts, you can read them here and here. We're not over by a long shot, so let's strap ourselves in!

Today, we're going to start looking at using modern JavaScript syntax and features, as well making sure we write consistent code. This will allow us to use the latest features and make sure we're writing our code neatly and precisely!

Setting Up EditorConfig

We're going to start off with making sure the way our code is typed is consistent across all editors. This is especially useful when you have multiple developers in the same project, especially if they use different editors, and make sure they keep to the same code rules. This is where EditorConfig comes in handy!

With EditorConfig, we can specify how code should be written, over all files and specific file types, with how many spaces or tabs should be in an indent, inserting new lines at the end of files, and more! Most editors now come with EditorConfig built in, but if yours doesn't, be sure to install EditorConfig for your Editor!

In our project folder, we can now write an .editorconfig file and place in the following rules. This specifies that all files need to have spaces for indents and have to be 2 spaces per indent, and make newlines at the end of our code files, except with JSON files we'll be making later.

# http://editorconfig.org
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.json]
insert_final_newline = ignore

Now that we've specified some editor rules, let's improve our code from the previous lesson!

Using ES6 Code

The first thing we can do right away, is update our code using the ES6 syntax. ES6 is a massive improvement to JavaScript, as it includes features that makes the writing of JavaScript easier, more readable, and has powerful new methods.

First thing we can do is update how we write our variables. In our previous code, we only used var to write our variables, but with ES6 we can write two different kinds of variables: const and let. Let's look at them!

const is used for variables that are constant and never change — you may have seen this before in languages like C++. let, on the other hand, is used for variables that can change from their initial value.

const five = require('johnny-five');

// Set `lightOn` to true as a default since our LED will be on
let lightOn = true;

// Make a new Board Instance
const board = new five.Board();

// When the board is connected, turn on the LED connected to pin 9
board.on('ready', function() {
  console.log('[johnny-five] Board is ready.');
 
 
 
 
 
 
 
    
    
  
  
 
}); 

In our code, we've updated our code to use JavaScript constants for Johnny-Five component objects, and we'll use let for the lightOn variable since it continuously changes.

Another thing we can update is any function statements — ES6 allows us the use the 'arrow' syntax. This makes the writing of functions simpler and more convenient.

// When the board is connected, turn on the LED connected to pin 9
board.on('ready', function() {
  console.log('[johnny-five] Board is ready.');

  // Make a new Led object and connect it to pin 9
  const led = new Led(9);

  // Make a new Button object assigned to pin 7
  // We also need to say it is a pullup resistor!
  const pushButton = new Button({
    pin: 7,
    isPullup: true,
  });

  // Switch it on!
  led.on();

  // If the button is pressed, toggle the LED on or off
  pushButton.on('down', () => {
    if (lightOn) {
      led.off();
      lightOn = false;
    } else {
      led.on();
      lightOn = true;
    }
  });

  // REPL object so we can interact with our LED
  this.repl.inject({
    // Control the LED via calling for the object
    led,
    // switchOn and switchOff functions to turn LED on and off using REPL
    switchOn: () => {
      if (lightOn) {
        console.log('[johnny-five] LED is already on!');
      } else {
        led.on();
        lightOn = true;
      }
    },
    switchOff: () => {
      if (!lightOn) {
        console.log('[johnny-five] LED is already off!');
      } else {
        led.stop().off();
        lightOn = false;
      }
    },
  });

  // When the board is closing, stop any LED animations and turn it off
  this.on('exit', () => {
    led.stop().off();
    console.log('[johnny-five] Bye Bye.');
  });

});

There is one caveat though — using the arrow syntax does not give the function its own context, so you can't use this! Because of...this...we can't apply the arrow syntax to the Board object — it requires function() for its 'ready' event, it needs the Board context for specific things!

Getting ready for the future with Babel

Now, currently, our current ES6 code works in our Node.JS runtime fine, but it could do more! The problem is, since Node.JS uses Chrome's V8 engine for JavaScript, that means it's not entirely up to date with ES6's awesome and fancy fancy features. However, we can use them now using a great development tool called Babel!

Babel allows us to code with current and upcoming JavaScript features, and can also output our code to browser-ready code for extra support! This will be useful later when it comes to the browser, but right now, we need to use it for ES6's module syntax.

In your CLI, add babel using Yarn as a development dependency.

yarn add --dev babel-cli babel-preset-env

We've added two packages here — babel-cli and babel-preset-env. Before we use babel, we need to also add a .babelrc file, which is needed to work with babel's API. In .babelrc, we can tell it which preset to use with the following:

{
  "presets": [
    "env"
  ]
}

Now that we've specified a preset for our Babel runtime, we can now use babel-cli! With babel-cli, we can compile our code into ES5 syntax, or run the Babel code from the CLI!

In our code, we'll change our first line of code to use the modules syntax.

import { Board, Led, Button } from 'johnny-five';

// Set `lightOn` to true as a default since our LED will be on
let lightOn = true;

// Make a new Board Instance
const board = new Board();

// When the board is connected, turn on the LED connected to pin 9
board.on('ready', function() {
  console.log('[johnny-five] Board is ready.');
  
  // Make a new Led object and connect it to pin 9
  const led = new Led(9);
  
 
  // We also need to say it is a pullup resistor!
  const pushButton = new Button({
    pin: 7,
    isPullup: true,
  });
  
 
});

Notice we've no longer stored the entirety of Johnny-Five into a variable, but we're importing specific objects into our file using the ES6 import syntax. Seem familiar to some of you who have used Python before?

Since we've imported specific objects, we can now replace lines of code. No longer do we need to use new five.Board(), for example. We can just do new Board() instead since we've imported that specific module!

Now, if we run the following in the CLI:

yarn babel-node index.js

Our Nodebot, with our updated ES6 code, should run without any problems! Neato!

Getting Into Node Scripts

We've made a lot of progress so far, but let's do something that will be useful for us later — adding a Node script. In your package.json file, you can add scripts that can then be run by Yarn instead of writing long commands using the CLI. This is especially useful for commands that can be very long and can be quite complicated!

Instead of writing yarn babel-node index.js all the time, why don't we put it into a simple start command?

"scripts": {
  "start": "babel-node index.js"
}

Now all we need to do is run yarn start, and it will run our babel command no problem! We'll be making more scripts later which will greatly benefit our development process.

Writing Consistent Code with ESLint

It helps a lot to write consistent code, and one way of achieving this is using a Linter. Linters use a specific set of rules when it comes to code, and it gives a guide on how to write them. For this, we're using ESLint, a very popular JavaScript Linter.

This will be useful for testing our code is correct and follows a set of rules for writing our code. This is especially helpful if the code will be released for production.

For this, we'll be using eslint-airbnb-base, a set of ESLint rules for JavaScript instead of writing our own. It's worth noting eslint-airbnb is the usual set of ESLint rules by Airbnb, but they contain rules for React and JSX. We only need eslint-airbnb-base for our code. Simply install them by running the following command.

npm info "eslint-config-airbnb-base@latest" peerDependencies --json | command sed 's/[\{\},]//g ; s/: /@/g' | xargs yarn add  --dev "eslint-config-airbnb-base@latest" 

This will install the latest version of Airbnb's base ESLint rules, and all dependencies required for them. In your project, make a file called .eslintrc.json, and this will contain our configuration of ESLint.

{
  "extends": [
    "airbnb-base"
  ]
}

Now we can run ESLint to look through our code using a ruleset, by simply running yarn eslint. But uh-oh! Looks like we have a few errors!

These warnings and errors show problems in our code and need to be fixed! Some perfectly simple ones to fix, like making sure we have comma dangles in return and making sure our file has a new line at the end, but others are a bit trickier since the code requires these features, like the console.log()!

Not to worry, if we put this at the top of our file:

/* eslint-disable no-console */
import { Board, Led, Button } from 'johnny-five';
// Set `lightOn` to true as a default since our LED will be on
let lightOn = true;

Then this will make our console error go away, especially since we need the console.log() and we can do it just for this file. However, other features, such as using function() in our code instead of the arrow syntax and padded blocks, may need to be all around our project. This is where we can specify rules of our own through .eslintrc.json and override some of the ones set via airbnb-base.

{
  "extends": [
    "airbnb-base",
  ],
  "rules": {
    "func-names": "off",
    "space-before-function-paren": "off",
    "padded-blocks": "off"
  } 
}

We should now get no errors in our code! Nice and clean, and with consistent rules so we can write code that's tidy.

Type Checking with Flow

Another thing to add is type checking — with type checking, we can make sure our types are consistent, i.e. that what is expected is a string, then it must be a string, otherwise it will throw an error. For this, we'll be installing Flow.

Flow will check over the code we've written and make sure all the data types are correct and consistent throughout all of our code. The following command will install the Flow as well as plugins for Babel and ESLint.

yarn add --dev flow-bin babel-preset-flow babel-eslint eslint-plugin-flowtype 

Once we've installed flow, we need to update our .babelrc for it to work with Flow.

{
  "presets": [
    "env",
    "flow"
  ]
}

We also need to update .eslintrc.json to work with Flow as well.

{
  "extends": [
    "airbnb-base",
    "plugin:flowtype/recommended"
  ],
  "plugins": [
    "flowtype"
  ],
  "rules": {
    "func-names": "off",
    "space-before-function-paren": "off",
    "padded-blocks": "off"
  } 
}

Finally, add an empty .flowconfig file in your project — and Flow will be ready to go! You can then add an annotation to files you want flow to check — in this case, we'll add this to our Nodebot script.

// @flow
/* eslint-disable no-console */
import { Board, Led, Button } from 'johnny-five';

Now simply run yarn flow, and hopefully there will be no errors! We can also add a test script to our package.json file to run ESLint and then run flow once it's done.

"scripts": {
  "start": "babel-node index.js",
  "test": "eslint ./ && flow"
},

Well done! You've now added modern JavaScript and code testing tools to your Nodebot!

Overview of updating our code

We've covered a lot here, but it's worth reviewing what's been done here. Here, we've added tools like EditorConfig to have consistent writing to our code, updated our code with ES6 features, and added Babel to use new JavaScript features.

We've also added tools for testing, with ESLint for testing the consistency of our code following specific rules and Flow to make sure our code types are correct. This will be very useful when we add more code and in larger projects!

Next Time...

We're going to be making a Node Server and make a simple web interface for our Nodebot! We'll be covering the process of making a simple server, building a page with HTML, and using sockets. This is where it's going to get exciting, so don't miss out!

I bet you totally can't wait for the next part!

Are you really looking forward to learning more about JavaScript and Hardware? Why wait for it to be released publicly? Pledge to my Patreon and you'll be able to see it days before anybody else!

Alternatively, you can follow me on Twitter, like my page on Facebook, or subscribe to my mailing list to know when it's out! Also, if you want to help me out, you can donate to my PayPal, it helps me make these articles and code! See you next time!

Code

index.jsJavaScript
The updated version of our simple Nodebot using ES6 and Babel!
// @flow

/* eslint-disable no-console */
import { Board, Led, Button } from 'johnny-five';

// Set `lightOn` to true as a default since our LED will be on
let lightOn = true;

// Make a new Board Instance
const board = new Board();

// When the board is connected, turn on the LED connected to pin 9
board.on('ready', function() {
  console.log('[johnny-five] Board is ready.');

  // Make a new Led object and connect it to pin 9
  const led = new Led(9);

  // Make a new Button object assigned to pin 7
  // We also need to say it is a pullup resistor!
  const pushButton = new Button({
    pin: 7,
    isPullup: true,
  });

  // Switch it on!
  led.on();

  // If the button is pressed, toggle the LED on or off
  pushButton.on('down', () => {
    if (lightOn) {
      led.off();
      lightOn = false;
    } else {
      led.on();
      lightOn = true;
    }
  });

  // REPL object so we can interact with our LED
  this.repl.inject({
    // Control the LED via calling for the object
    led,
    // switchOn and switchOff functions to turn LED on and off using REPL
    switchOn: () => {
      if (lightOn) {
        console.log('[johnny-five] LED is already on!');
      } else {
        led.on();
        lightOn = true;
      }
    },
    switchOff: () => {
      if (!lightOn) {
        console.log('[johnny-five] LED is already off!');
      } else {
        led.stop().off();
        lightOn = false;
      }
    },
  });

  // When the board is closing, stop any LED animations and turn it off
  this.on('exit', () => {
    led.stop().off();
    console.log('[johnny-five] Bye Bye.');
  });

});
package.jsonJSON
The package file used in this tutorial.
{
  "name": "basic-nodebot",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "scripts": {
    "start": "babel-node index.js",
    "test": "eslint ./ && flow"
  },
  "dependencies": {
    "johnny-five": "^0.13.0"
  },
  "devDependencies": {
    "babel-cli": "^6.26.0",
    "babel-eslint": "^8.2.1",
    "babel-preset-env": "^1.6.1",
    "babel-preset-flow": "^6.23.0",
    "eslint": "^4.9.0",
    "eslint-config-airbnb-base": "^12.1.0",
    "eslint-plugin-flowtype": "^2.42.0",
    "eslint-plugin-import": "^2.7.0",
    "flow-bin": "^0.64.0"
  }
}
.editorconfigJavaScript
The EditorConfig code for consistent typing in code.
# http://editorconfig.org
root = true

[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.json]
insert_final_newline = ignore
.babelrcJSON
{
  "presets": [
    "env",
    "flow"
  ]
}
.eslintrc.jsonJSON
{
  "extends": [
    "airbnb-base",
    "plugin:flowtype/recommended"
  ],
  "plugins": [
    "flowtype"
  ],
  "rules": {
    "func-names": "off",
    "space-before-function-paren": "off",
    "padded-blocks": "off"
  } 
}

Schematics

Simple Nodebot
Same circuit as Part One — no changes!
First nodebot f4zqgjryd6

Comments

Similar projects you might like

Basic Arduino + JavaScript (Workshop)

by Alex Glow

  • 11,873 views
  • 1 comment
  • 27 respects

React and Johnny-Five Traffic Lights

by Iain

  • 2,041 views
  • 0 comments
  • 5 respects

Buzzer Alarm System With Help Of Arduino

by Team ONYX

  • 37,882 views
  • 5 comments
  • 21 respects
Add projectSign up / Login