Enjoying the Vue: Frontend Design for Embedded Systems

vuejs-logo_2

In previous articles, we’ve discussed the basics of embedded systems web development, showing some fundamental concepts of HTML, CSS, and JS technologies. Although these are the pillars for any web-based application, nowadays, there’re a variety of options that we can choose from to create dynamic and attractive user interfaces in less time. These tools are known as frameworks, and in this article we’ll learn one which is very much in line with the requirements of embedded systems; this is Vue.

Perfect Timing. Try Our ARM® Embedded Dev Kit Today.

Netburner ARM Cortex M7 embedded Development Kit for IoT product development and industrial automation.

Or, learn more about NetBurner IoT.

We’ll talk about how to implement Vue in your web interface projects using NetBurner devices, with a perspective focused on embedded systems developers with little to no experience in the world of web systems.

Introduction

Vue is an open-source framework for user interface design based on JavaScript. It was created by Evan You (a former Google employee) in 2014. It provides a declarative, component-based programming model that enables the creation of scalable applications for small and large projects.   

At only seven years old, Vue is a younger framework compared to Angular (2010) and React (2013). However, that has not prevented it from gaining popularity among developers today. For example, companies such as Alibaba, Trivago, Netflix, and Adobe have started migrating some of their services to incorporate Vue. 

Image 1 shows the popularity of VUE compared to Angular and React based on the number of stars on GitHub.

Image 1: Web frameworks trend based on Github stars.

Why Vue?

We’ve already pointed out that Vue is not the only choice of frameworks we have for user interface design based on web technologies, so why choose Vue over Angular and React? This could be a never-ending discussion because each one has exciting features. In this article, we’ll focus on Vue because its features fit well with the requirements of embedded systems. We outline and examine some of those features below. 

Learning Curve

For those who come from embedded systems development, starting with web development can be a nightmare due to the many tools and technologies out there. That’s why I consider the time it’ll take us to learn a new technology a vital point; we can’t afford to spend one year learning a tool that will surely be supplanted by newer technologies as soon as we master it.

Vue is easy to learn if you have the basics of HTML/CSS and JavaScript. You can start developing applications in a couple of months; if you are very dedicated, you could even start converting your old web projects to Vue in a few weeks. 

But you must be careful. Even though it’s a simple framework to learn, the better your JavaScript proficiency, the better your Vue code will be. Poor code could make your application difficult to test and maintain.

Progressive Framework

This is one of the most interesting features of using Vue. It’s a progressive framework. That is, you can progressively migrate an application from another framework written with native HTML/CSS and JS.

What does this mean for us? This means that Vue can work in one section of your project, and everything else works with another technology without having conflict between the two pieces. Image 2 shows an example of this. Only one component (blue) is handled by Vue and everything else by another library or framework.

Figure 2: Example of progressivity in VUE

This is very useful for embedded systems because if you already have a working system and want to add more functionality, it’s enough to create a component managed by Vue without having to remake the complete application from scratch.

Documentation

One of the critical components to have when you start learning to use new technology is good documentation with which you can understand the specific topics. Vue provides well-organized documentation, starting from the basics and going to more advanced topics. You can find the documentation on the official Vue website. It contains everything you need to use this framework.

In addition to the official documentation, you can find various videos and tutorials on the web.

Versatility

This section describes some benefits of working with Vue. Unlike other frameworks, it offers certain freedoms, which allows for a high level of customization based on your coding style or your team’s standards.

Coding Language

Originally VUE ran on native JavaScript, making it very easy to use if you already knew how this programming language works. With Vue 3.0, you can also write code using Typescript, a JavaScript superset that allows you to add additional functionality. This includes adding variable typing, using interfaces, object-oriented code in an effortless way, etc.

API Styles

The creation of components in Vue can be done in two ways:

  • Option API 
  • Composition API. 

Options API: The traditional way of working with Vue is the one I strongly recommend starting with. It’s about organizing a component’s information in properties that contain the object. Through these properties, you add functionality to the application.   

A component based on the Options API looks like this:

				
					<script>
export default {
  // Properties returned from data() becomes reactive state
  // and will be exposed on `this`.
  data() {
    return {
      count: 0
    }
  },
 
  // Methods are functions that mutate state and trigger updates.
  // They can be bound as event listeners in templates.
  methods: {
    increment() {
      this.count++
    }
  },
 
  // Lifecycle hooks are called at different stages
  // of a component's lifecycle.
  // This function will be called when the component is mounted.
  mounted() {
    console.log(`The initial count is ${this.count}.`)
  }
}
</script>
 
<template>
  <button @click="increment">Count is: {{ count }}</button>
</template>
				
			

Composition API: This is the new way of creating components in VUE. Unlike the Options API, there’s only one attribute where all of the application’s functionality is placed. This allows it to have more fluid code, and the form is more similar to traditional JavaScript. 

A component based on Composition API looks like this:

				
					<script setup>
import { ref, onMounted } from 'vue'
 
// reactive state
const count = ref(0)
 
// functions that mutate state and trigger updates
function increment() {
  count.value++
}
 
// lifecycle hooks
onMounted(() => {
  console.log(`The initial count is ${count.value}.`)
})
</script>
 
<template>
  <button @click="increment">Count is: {{ count }}</button>
</template>
				
			

Once Vue is understood through the Options API, I recommend using the Composition API for all components created in the future. This is because you have more versatility in using the advanced features of Vue with this API. 

How To use Vue with NetBurner Devices?

In this section, we’ll show how to use Vue on your favorite NetBurner board, so you can bring your next web-based user interface to the world quickly and easily.  We’ve modified the existing default application for the MODM7AE70 development board, but it will work for any NNDK 3.x.x based board.

To demonstrate the progressiveness and ease of implementing Vue, we’ll change a small part of the code in the LED/Switch Control Example section to work with Vue. The remaining application will work as is without any changes. Image 3 below shows the current LED/Switch Control Example page, and enclosed in red is the section to which we’ll add Vue functionality.

Currently, the LED control section uses the CPPCALL dynamic web function, which is a handy feature. The problem is that for this to work, there must be a browser reload for the new value to be displayed, which may not be very appealing to the user. Although this can also be solved with WebSockets, we want to give you another option for your toolbox.   

Figure 3: LED section to which VUE functionality is to be added

Build current example

The first thing you need to do is to compile and load (you can use NBEclipse or command line) the example, which can be found in: 

\nburn\examples\PlatformSpecific\MODM7AE70\MODM7AE70\MODM7AE70FactoryApp

Open a web browser on your computer that is on the same network as your development board and access the IP of your device (this can be found by going to discover.netburner.com). You’ll see a page like the one shown in Image 4.

Figure 4: Example factory home page

Adding an HTTP Endpoint

With the above, you have verified that your system is ready. Before you add Vue, first, you need to make some changes in the firmware. Add an HTTP endpoint to allow communication through the HTTP GET verb. To do this, go to the src/webfuncs.cpp file and add the following code at the end.

				
					/*---------------------------------------------------------------------------------------
 * Callback to intercept a GET request for URL leds-vue*. The purpose of this callback
 * is to change the status of the LEDs on the development board and get an echo of what
 * is received.
 *
 * - Sends a JSON header to the browser to specify the content that follows is application/json
 * - Change the status of the LEDs
 * - Create a small JSON to respond with the current value sent.
 * - A return value of 1 tells the system the HTML request was handled by the callback
 *
 * Notes:
 * - HTTP_Request is a structure containing detailed information of the request
 *--------------------------------------------------------------------------------------*/
int callbackGetLeds(int sock, HTTP_Request &pHttpRequest) {
  iprintf("Executing GET request callback function: callbackPostLeds\r\n");
  iprintf("Request URL: %s, from: %I\r\n", pHttpRequest.pURL, pHttpRequest.client_IPaddr);
 
  // The URL will have the format: "leds-vue?number", where the value
  // of "number" will store the LED information. The following code
  // will test for the '?' character. If one exists, then the
  // number following the '?' is assumed to contain a value
  // indicating which LEDs are lit. If no '?' is in the URL, then
  // the LEDs are initialized to a known state.
  int32_t urlEncodeOffset = 9;
  uint8_t v = 0xAA;
 
  if ((*(pHttpRequest.pURL + urlEncodeOffset)) == '?') {
    v = (uint8_t)atoi((char *)(pHttpRequest.pURL + urlEncodeOffset + 1));
  }
 
  putleds(v & 0xFF);
 
  // Create respond string to client with the JSON Conten-Type
  // And the JSON object with the value of the LEDs
  char leds_string[50];
  sprintf(leds_string, "{\"leds\":%u}", v & 0xFF);
  writestring(sock, "HTTP/1.0 200 OK\r\nPragma: no-cache\r\nContent-Type: application/json\r\n\r\n");
  writestring(sock, leds_string);
 
  // Notify system we handled the GET request
  return 1;
}
 
/*
 * Declare the callback function. Parameters:
 *   leds-vue*          URL to intercept
 *   callbackGetLeds    Pointer to the callback function
 *   tGet               HTTP Request Type (ref HTTP_RequestTypes)
 *   0                  User Access Group, 0 = no password
 *   true               When to call (beforeFiles parameter):
 *                        true:  Always called for the specified URL
 *                        false: Only called if the if the requested URL cannot be satisfied elsewhere
 */
CallBackFunctionPageHandler getHandlerLedsVue("leds-vue*", callbackGetLeds, tGet, 0, true);

				
			

This code adds an interceptor to the URLs with the format leds-vue*, which calls a callback (callbackGetLeds) that will be in charge of controlling the state of the LEDs on the development board.

Adding the VUE Library

VUE is a JavaScript library, so it’s added to the project with the tag. There’re two ways to do this:

  • Using a Content Delivery Network (CDN): This requires the system to have an internet connection but saves memory space on the microcontroller. You can find the source here
  • Embedded in the microcontroller flash: This does not require an internet connection but requires sufficient space available in the flash memory. The library minified for version 3.2.33 has an approximate weight of 160Kb. 

In this article, we’ll use the embedded way. You can download the minified version of the library here. In your project, inside the html/js folder, add a file called “vue.global.min.js” and paste the content of the Vue library. 

Open the html/led.html file, and add the library obtained before at the end of the tag.

				
					  <script type="text/javascript" src="js/vue.global.min.js"></script>
				
			

Adding the Vue Application Section

The library by itself does nothing. It is necessary to assign a space where the library will have domain. To do this, open the html/led.html file and look for the following section

				
					 <table id="lights" class="led" align="center">
      <tr>
        <!--CPPCALL WebLeds -->
      </tr>
    </table>
				
			

This current section controls the LEDs we want to replace, so delete it and add the following instead.

				
					 <div id="app_vue">
      
 </div>
				
			

This section will be the one that will control VUE. This must be identified by a unique id which will be used later to tell VUE where the application will be executed (in this case, it’s called “app_vue”, but it can be any name). Outside this section, everything will continue to work the way it was before, and VUE will only be able to modify and read values within this area.

Adding VUE application code

Once the VUE work area is ready, it’s time to create the application code. To do this inside the html/js folder, create a file called “vue-app.js” and copy the following code.

				
					const { createApp } = Vue;
 
createApp({
  /** Reactive data */
  data() {
    return {
      leds: 0,
    };
  },
 
  /** Methods */
  methods: {
    toggleLed(index) {
      this.getLeds(this.leds ^ (1 << index));
    },
 
    async getLeds(value) {
      // Create URL
      let endpoint = "/leds-vue";
      if (led >= 0) endpoint += `?${value}`;
 
      // Send request over HTTP
      const response = await fetch(endpoint);
      const data = await response.json();
 
      // Get the new value of leds
      this.leds = data?.leds ?? 255;
    },
 
    getImageLedStatus(state) {
      return `images/${state ? "on" : "off"}.png`;
    },
  },
 
  /** LifeCycle  */
  mounted() {
    this.getLeds(170);
  },
}).mount("#app_vue");
				
			

This code has all the necessary functionality to change the status of the LEDs by using the following methods:

  • getLeds: It is in charge of requesting and changing the status of the LEDs by sending an HTTP request through the endpoint “leds-vue?state” (which you previously configured in the board).
  • toggleLed: Toggles the bit value of the corresponding LED and calls the getLeds function.
  • getImageLedStatus: Gets the value of the image depending on the current state of the LED.
  • mounted: Vue hook executed when the application is already mounted in the web client.

At the end, you can see the mount method, which specifies the ID of the HTML section where this application will be mounted; this value must be the same that you assigned in the previous step. 

For all this to work, it’s necessary to open the html/led.html file and add the application file at the end of the tag.

				
					  <script type="text/javascript" src="js/vue-app.js"></script>
				
			

Adding the Vue Application to HTML

To finish, the only thing you have to do is execute the methods created before. To do this, add the following HTML inside the app_vue section within the html/led.html file. This is necessary to create the LEDs and give them functionality.

				
					      <table id="lights" class="led" align="center">
        <tr>
          <td v-for="n in 8" @click="toggleLed(n-1)"> <img class="br-lazy" src="data:image/svg+xml;utf8,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%200%200'%3E%3C/svg%3E" data-breeze="getImageLedStatus(leds & (1 << (n-1)))" :src="getImageLedStatus(leds & (1 << (n-1)))"></td>
        </tr>
      </table>
				
			

Testing Code

Everything is ready, just recompile the project. It’s recommended to do a clean build. Once the code is loaded onto the development board, test the new function of the LEDs. Now without refreshing the page, you’ll see the change in the state of the LED.

Wrapping Up

 Vue is an easy framework to implement in our current projects and designs. While it’s required to know the syntax and features to use, the good news is that there’re many courses, tutorials, and excellent documentation on how to use it. One of the main advantages is that we do not have to redesign our entire UI from scratch. Instead, we can gradually change the features you want to modify or add more interaction.   

We hope this article will be helpful so that you can add a more dynamic UI using NetBurner devices and Vue in your future applications and projects.  

We would like to hear from you, don’t be a stranger and let us know what topics you would like to see in future articles! If you would like to share a project you are working on, you can drop us a comment below, or if you want to contact us directly, feel free to do it here.

About the Autor

Jordan Garcia

Jordan Garcia

Senior Embedded Firmware Developer at Luxoft.

IoT, embedded firmware, and industrial automation enthusiast.

Reader, dancer, swimmer, and dog lover.

Share this post

Subscribe to our Newsletter

Get monthly updates from our Learn Blog with the latest in IoT and Embedded technology news, trends, tutorial and best practices. Or just opt in for product change notifications.

Leave a Reply
Click to access the login or register cheese