LightningChart JSCreating an Arduino Dashboard for Industrial Monitoring

TutorialVisualizing industrial data in an Aurduino Dashboard using LightningChart JS

Written by a human | Updated on April 24th, 2025

Arduino Dashboard for Industrial Monitoring

In this article, we’ll be working with Lightning Chart JS and TypeScript. Our goal is to create an Arduino dashboard that displays four different charts, each with its own dataset.

We’ll be creating a 3D scatter chart, a data grid, a pie chart, and a line chart. All these charts will show data collected from an ambient telemetry sensor. Imagine we need to monitor or analyze environmental data in an industrial area—things like the temperature and humidity generated by equipment, pipes, and other machinery.

I’ve taken on the task of finding a dataset that allows us to work with real data and format it appropriately so Lightning Chart JS can display it on each chart. Below, I’ve shared a link to an author who explains the configuration process for their sensors and provides a more detailed look at the data collected available on Kaggle.

On my end, I’ve also worked with microcontrollers like Arduino, and I hope to share my knowledge in the future about how to build a sensor and interact with users through software. But for now, let me give you a quick explanation of how a microcontroller works. I’ll focus on Arduino since that’s the one I’m most familiar with.

Project Overview

Here is a video of the final Arduino dashboard:

zip icon
Download the project to follow the tutorial

What is Arduino?

Arduino is a microcontroller that can interact with and collect information from a physical object of study using sensors. It can also perform various actions through code that’s programmed and stored within it. This data can then be transmitted or saved to a computer, where it can be processed and displayed to the user through specialized software.

arduino-dashboard-arduino-system

There are many types of sensors, such as temperature, vibration, and motion sensors. Each sensor transmits a signal that can be interpreted as numerical values, Booleans, strings, etc. Within the Arduino, we can program actions or functions to format and process these values. Other physical components, like lights, LCD screens, and speakers, can also be controlled. These components can perform actions based on the values obtained from the sensors and their capabilities.

How to interact with the sensor, computer, and software?

Well, the simplest and most common way is to keep the sensor connected to a computer. The computer will be receiving the signal from the sensor constantly, so we will only have to access it to be able to manipulate it. Some different languages and frameworks will help us with this task. In this case, I have always worked with .NET which allows us to access the ports of our computer, using the namespace System.IO.Ports.

Once accessing the Arduino port, we can obtain the values that we have programmed within Arduino. It will also be possible to execute actions within our sensor. For this, we will have to exchange values between variables declared on both sides. Once the communication process between Arduino and .NET is controlled, we can format our data source. This format must be able to be read by our front end. If your front end communicates remotely, you will need to create an API that transmits HTTP responses in a JSON format.

If it is local, you can create a JSON in a local path, which is shared with your front end, and it can load the JSON file to display it on the dashboard. In this article, we will simulate the last option. We will have 3 JSON files within our project path, which will be read and formatted for our charts. These files will have the information collected by the environmental sensors.

Maybe in another article, we can program the communication of .NET and Arduino. If you are interested in this type of development, don’t forget to send us your feedback and ask for it, this would help a lot!

I will not explain the logic of Pie, Scatter, and Line charts, as there are articles dedicated to each of them, so I recommend that you visit our tutorial blog. Before starting with the code, we will review the logic of the datasets a little.

Monitoring Industrial Machinery

Much of what has been explained about Arduino could help us understand the topic of industrial monitoring. Industrial monitoring is known as the collection of data from industrial equipment, through the installation and communication of sensors to a dedicated server. Industrial monitoring is of the utmost importance, due to the danger that can be generated if failures are not predicted in advance. In the industrial sector, Arduino dashboards are common and their development is highly important for data processing and monitoring.

The data from the sensors is interpreted in specialized software, which can show us abrupt changes in levels of pressure, temperature, vibration, etc. Depending on the type of industrial equipment, the engineer in charge can identify future problems, based on the increase or decrease of some key parameters.

How do industrial machinery monitoring systems work? 

As I explained, in the interaction section between sensors and computers, each sensor is in constant communication with a server. This communication can be wired or wireless, using component devices that allow it (For example, WIFI antennas)

The server would have to be programmed to obtain these values ​​and process the data for use in monitoring software. As I commented on the example of interaction between Arduino and .NET, .NET offers us access to the ports of our computers. This access will allow us to obtain the data transmitted by the sensor and interact with it.

How can you visualize data from industrial machinery monitoring systems using an Arduino dashboard?

The answer lies in the type of monitoring software and its logic for processing data. These monitoring systems rely on data from various sensors, which can be stored in different formats, such as flat files or databases.

The monitoring systems are responsible for formatting this data, performing necessary calculations, and displaying the results in tables and graphs. Users should be able to reinterpret these values and interact effectively with the monitoring systems. Some monitoring systems even allow for sensor sensitivity configuration, enabling users to obtain values that better align with their specific study criteria.

An Arduino dashboard can enhance this process by providing a user-friendly interface for visualizing and interacting with the data in real-time, making it easier to analyze and derive insights from industrial machinery monitoring systems.

Dataset

Data was generated from a series of three identical, custom, breadboard-based sensor arrays. Each set was connected to a Raspberry Pi device. Each of the three IoT devices was placed in a physical location with varying environmental conditions.

Sensor readings include temperature, humidity, carbon monoxide (CO), liquefied petroleum gas (LPG), smoke, light, and motion. The data covers the period from 07/12/2020 at 00:00:00 UTC to 07/19/2020 at 23:59:59 UTC. There are a total of 405,184 rows of data. Sensor readings were published as a single message, using the ISO standard Message Queuing Telemetry Transport (MQTT) network protocol. Below is an example of the payload of an MQTT message. Data source.

}
	"data": {
		"co": 0.006104480269226063, 
		"humidity": 55.099998474121094,
		"light": true,
		"1pg": 0.008895956948783413,
		"motion": false,
		'smoke": 0.023978358312270912,
		"temp": 31.799999237060547
	},
	"device_id": "6e:81:c9:d4:9e:58",
	"ts": 1594419195.292461
}

Columns

There are nine columns in the dataset.

arduino-dashboard-columns-data

JSON Files

Inside this Arduino dashboard monitoring project you will find the following files:

  1. highly_variable_temperature_humidity
  2. stable_conditions_cooler_humid
  3. stable_conditions_warmer_dryer

Each file has been created based on the CSV document provided by the author. Each file corresponds to each sensor used by the author, therefore, in each chart, we will have 3 data series, and depending on the chart, 1 or 2 specific properties will be used.

For the 3D scatter chart, we will use the “humidity” and “temp” properties to compare the temperature values of each sensor, in relation to the percentage of humidity in the environment. In the Pie chart, we will use the “Light” property to show the behavior of light on each sensor. The line chart will show us the carbon monoxide level obtained by each sensor.

Template Setup

1. Download the template provided to follow the tutorial.

2. After downloading the template, you’ll see a file tree like this:

arduino-dashboard-project-folder

3. Open a new terminal and run the npm install command

4. It is important to keep the configuration in the tsconfig.json file. This configuration will help you to import JSON files as data objects.

Getting Started

We recommend you use and update to the most recent versions of LightningChart JS and XYData. This is because some LightningChart JS tools do not exist in previous versions. In the project’s package.json file you can find the LightningChart JS dependencies:

"dependencies": {
"@arction/lcjs": "^5.2.0",
"@arction/xydata": "^1.4.0",
}

1. Importing libraries

We will start by importing the necessary libraries to create our chart.

import { AxisTickStrategies, LegendBoxBuilders, PieChartTypes, SliceLabelFormatters} from "@arction/lcjs";
import { setHTMLComponents } from "./htmlComponents";
import { numberToDate, getMinMaxValues } from "./utils";

var HighlyTempHumidity = require('./highly_variable_temperature_humidity.json');
var stableCoolerHumid = require('./stable_conditions_cooler_humid.json');
var stableWarmerDryer = require('./stable_conditions_warmer_dryer.json');

// Import LightningChartJS
const lcjs = require('@arction/lcjs')

// Extract required parts from LightningChartJS.
const { lightningChart, Themes } = lcjs

2. Add license key (free)

Once the LightningChart JS libraries are installed, we will import them into our chart.ts file. Note you will need a trial license, which is free. We would then add it to a variable that will be used for creating the JavaScript dashboard object.

let license = undefined
try {
    license = 'xxxxxxxxxxxxx'
} catch (e) {}

Chart.ts

This file will contain the code for our Arduino dashboard charts, which you’ll notice functions much like a configuration file, where we simply declare the properties of LightningChart JS. In some sections, we’ll need to map the datasets we’re using, and this could be the most complex part of the code. First, we’ll need to declare a few variables:

var theme = Themes.lightNature;
var pointInterval = 100;
var fullData = [
    {
        name:'HighlyTempHumidity',
        data:HighlyTempHumidity
    },
    {
        name:'stableCoolerHumid',
        data:stableCoolerHumid
    },
    {
        name:'stableWarmerDryer',
        data:stableWarmerDryer
    }    
]

The Theme variable will store the theme used across all the charts, so we won’t need to update the theme property for each individual declaration in the code.

The pointInterval variable will help us filter the values from each dataset. Each dataset contains a large number of data points because the sensors continuously record values, meaning many of them show little to no variation. I’ve set an interval of 100 units, meaning we’ll only take every 100th value. This reduces the saturation of points or lines, making the charts easier to analyze. This value can be adjusted at any time, and all charts will update once the change is saved.

The fullData array will contain the three previously imported datasets, allowing us to apply conditions to each of them in charts that use multiple series. Once our variables are initialized, we’ll call the following methods:

setHTMLComponents();
linechart();
scatter3DChart();
pieChart("HighlyTempHumidity");
dataGridChart("HighlyTempHumidity");

Each chart has been wrapped inside a method to manipulate its execution. The setHTMLComponents method is in another TypeScript file and will help us create the HTML container and its grids. Below, I will explain each of the methods, but in order not to extend this article too much, I will explain only the code that has not been previously shown.

LineChart()

For this Arduino dashboard monitoring project, we will add a line chart. Here’s an example of the series:

function linechart()
{
    var maxValX = -Infinity;
    var minValX = Infinity;
    var maxValY = -Infinity;
    var minValY = Infinity;

    const lineChartContainer = document.getElementById('lineChartContainer')

The maximum and minimum variables will help us assign a start value and an end value to our X-Y axes. Since our HTML component method was executed first, we can now access the container of our line chart.

const line = lightningChart({license:license})
    .ChartXY({
        theme: theme,
        container: lineChartContainer
    })
    .setTitle("Carbon Monoxide")

We will create our XY chart object, assigning the global variable theme and the container previously obtained. Now we will have to map our dataset for this Arduino dashboard application:

for(const dataset of fullData)
    {
        let counter = 0;
        let interval = 0
        let lineData = [];   

        for(const obj of dataset.data)
        {
            if (counter === interval) 
            {
                interval = interval + pointInterval;
                const x = new Date(0).setUTCSeconds(obj.ts)
                const y = Number(obj.co)
                lineData.push({ x, y });
            }
            counter++;
        }
        
        let minmax = getMinMaxValues(lineData, minValX, maxValX, minValY, maxValY);

        // Update overall min/max values
        minValX = minmax.minValX;
        maxValX = minmax.maxValX;
        minValY = minmax.minValY;
        maxValY = minmax.maxValY;

        //Creating the line series
        line.addLineSeries().setName(dataset.name).add(lineData);
    }

This process will be done for each data set in the fullData array. We will simply obtain the timestamp and CO (carbon monoxide) values. The timestamp value will have to be converted to a numeric value, which is necessary for our X-axis. Finally, the maximum and minimum values ​​of the series are obtained and added to the line series.

line.getDefaultAxisX()
    .setTickStrategy(AxisTickStrategies.DateTime)
    .setInterval({
        start: minValX,
        end: maxValX,
    })
    .setTitle('Timestamp of Reading')

We configure our X-axis, assigning the DateTime strategy, which requires dates converted to numerical values. The intervals indicate from which date our chart will focus and to where it will end.

line.getDefaultAxisY()
    .setTitle('Carbon Monoxide')
    .setInterval({ start: minValY, end: maxValY, stopAxisAfter: true })

For our X-axis, we will not assign a strategy, which means that by default numerical values ​​will be used.

line.setAutoCursor((cursor) =>  cursor.setResultTableAutoTextStyle(true)
                                            .setTickMarkerXVisible(false)
                                            .setTickMarkerYAutoTextStyle(true))

We add the results table to our series. This table will show the X-Y values ​​of each point:

arduino-dashboard-XY-values

We add the legendBox:

line.addLegendBox()
        // Dispose example UI elements automatically if they take too much space. This is to avoid bad UI on mobile / etc. devices.
        .setAutoDispose({
            type: 'max-width',
            maxWidth: 0.3,
        })
        .add(line)
}
arduino-dashboard-legendbox

Scatter3DChart()

For this Arduino dashboard monitoring project, we will add a 3D scatter chart. Here’s an example of the series:

We create a new chart type object:

let scatterChart = lightningChart({license:license})
    .Chart3D({
        theme: theme,
        container: containerChart1
    })
    .setTitle("Humidity - Temperature July 2020")

This object will now be chart3D, which means that it will be a chart with the ability to display 3 axes, that is, generating a three-dimensional cube.

let legendBoxPoints = scatterChart
.addLegendBox(LegendBoxBuilders.VerticalLegendBox);

We generate an instance of the legend box object, this is created outside the mapping loop, to avoid tripling the object.

for(const dataset of fullData)
    {
        let points = [];       
        let counter = 0;
        let interval = 0

        for(const obj of dataset.data)
        {
            if (counter === interval) 
            {
                const x = new Date(0).setUTCSeconds(obj.ts);
                const y = obj.temp;
                const z = obj.humidity;
                const size = 2;
                points.push({ x, y, z, size });
                interval = interval + pointInterval;
            }
            counter++;
        }

For each data set, we will create an object with properties X, Y, and Z. The values ​​of X will be those of the timeStamps, the values ​​of Y will be those of temperature, and the values ​​of Z will be those of humidity. The size of the points will be in pixels. In the same way, we will obtain the values ​​of 100 by 100 using the pointInterval variable.

var serie = scatterChart
        .addPointSeries({
            individualPointSizeEnabled: true,
        })
        .setName(dataset.name)
        .add(points)
        
        legendBoxPoints.add(serie);

We create a series of points by assigning the dataset fullData[] and adding the points array, which contains our entire dataset already formatted. The IndividualPointSizeEnabled property lets us assign a custom size to each point. I’ve left this property set to true in case you want to implement different sizes for each point in your Arduino dashboard. Finally, we added the series to our legends box to complete the display setup.

arduino-dashboard-legendbox-series

Pie chart

Here’s the pie chart that will be featured in the Arduino dashboard application:

We will obtain the chart container:

const pieChartContainer = document.getElementById('pieChartContainer')

    const pie = lightningChart({license:license})
    .Pie({
        theme: theme,
        type:  window.innerWidth > 599 ? PieChartTypes.LabelsOnSides : PieChartTypes.LabelsInsideSlices,
        container: pieChartContainer
    })
    .setMultipleSliceExplosion(true)
    .setTitle('Light Detection - DataSet: '+dataSet)
    .setLabelFormatter(SliceLabelFormatters.NamePlusRelativeValue);

We will assign the theme and container for our Arduino dashboard. The chart type will be determined by the grid size (resolution). If the resolution is greater than 599, the labels will appear outside the slices; otherwise, they will be displayed inside. The setMultipleSliceExplosion property allows us to separate all the slices visually. Based on the dataSet argument passed to our pieChart() method, the appropriate dataset from the Arduino sensors will be selected for display.

switch (dataSet) {
        case 'HighlyTempHumidity':
            defaultData = HighlyTempHumidity
            break;
        case 'stableCoolerHumid':
            defaultData = stableCoolerHumid
            break;
        case 'stableWarmerDryer':
            defaultData = stableWarmerDryer
            break;
        default:
            defaultData = HighlyTempHumidity
            break;
    }

We create the object and the desired format of our data set:

let pieData: { name: string, value: number }[] = [
        { "name": "TRUE", "value": 0 },
        { "name": "FALSE", "value": 0 }
    ];

Mapping

for (const obj of defaultData) {
        if (counter === interval) 
        {
            if (obj.light === "TRUE") {
                pieData[0].value++;
            } else {
                pieData[1].value++;
            }
            interval = interval + pointInterval;
        }
        counter++;
    }
For each true value, it will be added and assigned to the true object in our pieData array. Otherwise, it will be added to the false object. We will then add our True and False objects as slices to the pie chart.
pieData.map((item) => pie.addSlice(item.name, item.value))

Now we will create our annotations, which will help us select the data set we want:

arduino-dashboard-annotations-UI-controls
const annotationMenu = document.createElement('div')

    pieChartContainer.append(annotationMenu)
    annotationMenu.style.position = 'absolute'
    annotationMenu.style.display = 'flex'
    annotationMenu.style.flexDirection = 'row'
    annotationMenu.style.margin = '50px';

For each data set, we will create a button, using the span component:

[
        { color: '#2596be', label: 'HighlyTempHumidity' },
        { color: '#873e23', label: 'stableCoolerHumid' },
        { color: '#009933', label: 'stableWarmerDryer' },
    ].forEach((item) => {

Each span component will have the same properties, and will only change in the color that we previously assigned:

const option = document.createElement('span')
        annotationMenu.append(option)
        option.innerText = item.label
        option.style.color = "#ffffff"
        option.style.textAlign = "center"
        option.style.height = 'auto'
        option.style.width = 'auto'
        option.style.fontFamily = 'Segoe UI'
        option.style.fontSize = '12px'
        option.style.backgroundColor = item.color
        option.style.marginRight = '10px'
        option.style.border = `solid ${pie.getTheme().isDark ? 'white' : 'black'} 1px`
        option.style.borderRadius = '5px'
        option.style.cursor = 'pointer'
        option.draggable = true
        option.onclick= () => {
            pieChart(item.label);
            dataGridChart(item.label);
        }

Each button will have an onClick event, which will execute the pieChart method and the dataGridChart method. This will build the chart from scratch, but with the data set that we have sent in the argument.

dataGridChart()

We will obtain the container and create the columns of our data grid:

const containerChart2 = document.getElementById('containerChart2')
const dataGridContent = [['Time', 'Carbon Monoxide', 'Humidity', 'Light', 'Liquid Petroleum Gas', 'Smoke', 'Temperature']]

In this data grid we will show almost all the values ​​obtained by the sensors. Now we will create the DataGrid object:

const dataGrid = lightningChart({license:license})
    .DataGrid({
        container: containerChart2,
        theme: theme,
    })

We create a loop to map our data set. Since we only want to show the values ​​in the data grid, creating an array with the values ​​in the exact order of their column will be enough.

for (const obj of defaultData) {
        if (counter === interval) 
        {
            dataGridContent.push([numberToDate(new Date(0).setUTCSeconds(obj.ts)), obj.co, obj.humidity, obj.light, obj.lpg, obj.smoke, obj.temp])
            interval = interval + pointInterval;
        }
        counter++;
    }

The dataGrid content array will be updated with each object in the data set. Finally, we add the dataGridContent to the data grid:

dataGrid.setTableContent(dataGridContent)

Finally, run the NPM START command on a new terminal to open the project on your local host.

Conclusion

Wow! This has been one of my favorite articles to write. It’s amazing to work with sensors and software at the same time, especially when building an Arduino dashboard. Being able to interpret real-world scenarios or behaviors through software is fascinating.

However, working on projects like this Arduino dashboard can be quite exhausting. Planning and building sensors is a complex and time-consuming task that requires a lot of learning and trial and error. On the software side, programming and processing sensor data—like temperature, pressure, and vibration—requires extensive study. Then, to top it off, developing an intuitive Arduino dashboard that displays the data clearly and provides functions for analysis adds another layer of complexity, especially for one person.

That’s where LC JS comes in. It makes creating a dashboard fast and visually appealing. The smooth axis behaviors, 3D object movements, and tooltips provide a comprehensive view of the data from your Arduino sensors. Once the charts are set up correctly, they handle much of the heavy lifting for you.

As you may have noticed, much of the LC JS implementation revolves around configuring chart properties. Of course, LC JS offers many more features, like advanced display options and axis behaviors, which you can explore further. If you’re interested in learning more, be sure to check out our other articles and download templates to deepen your understanding of LC JS and how to build a powerful Arduino dashboard.

Thanks for reading! Goodbye!

Omar Urbano Software Engineer

Omar Urbano

Software Engineer

LinkedIn icon
divider-light

Continue learning with LightningChart

Industrial Telemetry

Industrial Telemetry

Written by a human | Updated on April 14th, 2025IntroductionIn today's rapidly evolving world, industries are increasingly relying on advanced technologies to optimize their operations. One such technology that has gained significant traction in recent years is...

Xamarin Charts

Xamarin Charts

Written by a human | Updated on April 14th, 2025What is Xamarin?Xamarin.Forms is a cross-platform UI toolkit that allows us to create user interfaces that can be shared across Android, iOS, and Windows apps. Forms are part of the Xamarin ecosystem, which is a set of...

Data Acquisition System Application

Data Acquisition System Application

Written by a human | Updated on February 14th, 2026Data Acquisition System Application: Hi Speed DAQ ChartIn this article, we will be creating a Data Acquisition System application using a Hi-Speed DAQ chart and we will see how to add real-time source data. We will...