DEV Community

Cover image for Qwik & Arduino with Johnny Five
Fabio Biondi
Fabio Biondi

Posted on

Qwik & Arduino with Johnny Five

Some days ago I have shared some experiments I have recently done with Qwik and Arduino on my LinkedIn and Twitter profiles.

A lot of people asked me more details about it, so I wrote this article to explain what I did.

Anyway, as the post title suggests, we can control Arduino, Raspberry and other micro-controllers directly from a front-end application built in JavaScript 😱.

Johnny Five

Some times ago I have played with johnny-five, a JavaScript Robotics & IoT platform.
In short words, we can communicate with our Arduino or Raspberry by using JavaScript with a very friendly syntax.

For example, to blink a LED you can :

1) Connect a LED to PIN 13 of your Arduino board:

Image description

2) Create a JavaScript module, i.e. index.js:

const { Board, Led } = require("johnny-five");

// connect your board
const board = new Board();

// when board is ready
board.on("ready", () => {

  // Create a standard `led` component instance
  const led = new Led(13);

  // "blink" the led in 500ms
  // on-off phase periods
  led.blink(500);

});
Enter fullscreen mode Exit fullscreen mode

3) Run the code in your terminal

node index.js
Enter fullscreen mode Exit fullscreen mode

I have used Node v.18

Here you can find more details about the installation of Johnny Five and how the previous example works:

Johnny Five Get Started
• Johnny Five Examples


Qwik

Qwik is a full-stack web framework to create super-performing and SEO friendly applications.

One of its most interesting features is the server$ functions, that allow you to create a function that is always executed on the server.

server$ is a form of RPC (Remote Procedure Call) mechanism between the client and server, just like a traditional HTTP endpoint but strongly typed thanks to Typescript, and easier to maintain.
Source: Qwik server$ Documentation

Following I show you a very basic example of server$ function:

import { component$, useSignal } from '@builder.io/qwik';
import { server$ } from '@builder.io/qwik-city';

// executed on server
const serverGreeter = server$((firstName: string) => {
  const greeting = `Hello ${firstName}`;
  return greeting;
});

export default component$(() => {
  // Signal to contains the input value
  const text = useSignal('');

  return (
    <>
      <label>
        Your Name:
        <input bind:value={text} />
      </label>

      <button
        onClick$={async () => {
          // invoke the server$ function 
          // passing the input text value
          // when button is clicked 
          const greeting = await serverGreeter(text.value);
          alert(greeting);
        }}
      >
        greet
      </button>
    </>
  );
});
Enter fullscreen mode Exit fullscreen mode

Blink LED with Johnny Five & Qwik

Image description

Since the Qwik $server function always run on server, we can use any package designed to run in a Node.js environment.

So my first thought was:

maybe I can use Johnny Five directly on Qwik to control my Arduino

And yes, it worked! 😍


Let me show you how I did:

1) First, connect a LED to PIN 13 of your Arduino Board:

2) Create a new Qwik Project:

# create the project
npm create qwik@latest

# Run the project 
npm run dev
Enter fullscreen mode Exit fullscreen mode

This process creates a basic Qwik Project with a couple of routes.

3) Now we can open and update the default route component (routes/index.tsx):

  • create a button whose click we invoke the server function

  • import the "johnnyfive" package, create a Board instance and use its API to define the PIN 13 and blink the connected LED:

// routes/index.tsx
import { component$, useSignal } from '@builder.io/qwik';
import { server$ } from '@builder.io/qwik-city';

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

const board = new five.Board();

const arduinoBlink = server$(() => {
  // Define LED PIN
  const led = new Led(13);
  // Blink
  led.blink(555);
});


export default component$(() => {
  return (
    <>
      <button
        onClick$={async () => {
          // Blink LED
          // Invoke the server function 
          // when button is clicked
          await arduinoBlink();
        }}
      > BLINK LED </button>
    </>
  );
});
Enter fullscreen mode Exit fullscreen mode

Johnny Five Blink Example

LCD display

Johnny Five allow us to easily use sensors, LCDs, Servo / Motors, Joysticks and several other devices.

For example you can easily write into a LCD display as well:

// Define LCD PINS 
const lcd = new five.LCD({ pins: [7, 8, 9, 10, 11, 12] });
// Move the cursors to positio 0,0 and display a text
lcd.cursor(0, 0).print('Hello Qwik!');
Enter fullscreen mode Exit fullscreen mode

Image description

So, as you can imagine you can use this snippet of code in a Qwik server$ function as we did to blink the LED.

1) First, we can create a JS module in which we write the functions that contains the logic to communicate with the hardware and that are invoked by the server$ function:

// arduino.server.ts
import { server$ } from '@builder.io/qwik-city';
import five, { Board, Led } from 'johnny-five'

const board = new five.Board();

export const arduinoBlinkFn = () => {
  const led = new Led(13);
  led.blink(555);
};

export const arduinoLCDFn = server$((
  text1: string, text2: string
) => {
  // Define LCD PINS 
  const lcd = new five.LCD({ pins: [7, 8, 9, 10, 11, 12] });
  // display text1 in the first line of the display
  lcd.cursor(0, 0).print(text1);
  // display text2 in the second line
  lcd.cursor(1, 0).print(text2);
});

Enter fullscreen mode Exit fullscreen mode

2) Now we can simply create the UI in Qwik using JSX syntax, adding a couple of text inputs and a button to send both texts to the device.

The arduinoLCDFn() server function is invoked when the button is clicked, passing the values of both text inputs.

// routes/index.tsx
import { component$, useSignal } from '@builder.io/qwik';
import { server$ } from '@builder.io/qwik-city';

import { arduinoBlinkFn, arduinoLCDFn } from '~/arduino.server.utils';

const arduinoBlink = server$(() => {
  arduinoBlinkFn()
});

const arduinoLCD = server$((
  text1: string, text2: string
) => {
  arduinoLCDFn(text1, text2)
});


export default component$(() => {
  const textRow1 = useSignal('');
  const textRow2 = useSignal('');

  return (<>

    <button
      onClick$={async () => {
        await arduinoBlink();
      }}
    > BLINK LED </button>

    <input type="text" bind:value={textRow1} placeholder="row 1"  />
    <input type="text" bind:value={textRow2} placeholder="row 2"  />

    <button
      onClick$={async () => {
        await arduinoLCDFn(textRow1.value, textRow2.value);
      }}
    > WRITE ON LCD </button>

  </>);
});
Enter fullscreen mode Exit fullscreen mode

Here the final result:


Conclusion

Of course it's nothing special but this example demonstrates the simplicity and flexibility with which we can use any JavaScript modules within the server function.

How cool is that?
What do you think?

Top comments (5)

Collapse
 
francescoxx profile image
Francesco Ciulla

Super nerdy project Fabio, I love that! and I have an Arduino at home, maybe I should give it a try ahah

Collapse
 
fabiobiondi profile image
Fabio Biondi

thank you very much Francesco.
I'm curious to see what you'll invent 😅

Collapse
 
francescoxx profile image
Francesco Ciulla

I need a tool that makes you code while sleeping.

Thread Thread
 
fabiobiondi profile image
Fabio Biondi

🤣

Collapse
 
mikedepetris profile image
Mike De Petris • Edited

TOP level article as usual, thanks