DeviceScript and LCD screens
Tags: typescript, esp32, beginners, iot
Published: 2023-10-09 16:18:15


This article shows how to use [DeviceScript](https://microsoft.github.io/devicescript) to program a microcontroller (ESP32-C3), a temperature/humidity sensor (BME680) and a LCD character screen to build a tiny weather dashboard. This project does not require soldering or embedded skills.


![A LCD screen display temperature and humidity](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vwd6qt2jamr2zdvka1rp.png)

In a previous article, we looked at [using an OLED screen to display temperature readings using DeviceScript](https://dev.to/pelikhan/devicescript-and-oled-screens-102e).

## DeviceScript

[DeviceScript](https://microsoft.github.io/devicescript) brings JavaScript/TypeScript to tiny IoT devices such as the ESP32. DeviceScript provides a user friendly editing/debugging experience in Visual Studio Code.

You can follow along this tutorial without any hardware and use the simulators provided by DeviceScript. Otherwise, the parts needed are

-  [Xiao ESP32-C3](https://www.seeedstudio.com/Seeed-XIAO-ESP32C3-p-5431.html)
-  [Grove Shield for Xiao](https://www.seeedstudio.com/Seeeduino-XIAO-Expansion-board-p-4746.html)
-  [BME680 Grove](https://wiki.seeedstudio.com/Grove-Temperature_Humidity_Pressure_Gas_Sensor_BME680/)
-  [Grove LCD RGB Backlight](https://wiki.seeedstudio.com/Grove-LCD_RGB_Backlight/)


## Seeed Studio Xiao + Grove shield

The [Xiao ESP32-C3](https://www.seeedstudio.com/Seeed-XIAO-ESP32C3-p-5431.html) is a low-cost compact microcontroller board running the Espressif ESP32-C3.

The Grove shield for Xiao is a convenient base for the Xiao that provides an easy access to OLED screens, Grove connectors and battery charging.

DeviceScript provides a shield drivers that configures the pins and the OLED display for this hardware combo.

```ts
import { XiaoGroveShield} from "@devicescript/drivers"

const shield = new XiaoGroveShield()
```

## LCD screen as character screen

The Grove LCD screen supports 16 columns and rows of characters; it provides an I2C interface that dramatically reduces the complexity of connecting this kind of devices (just plug the grove connector and go). The [driver](https://github.com/microsoft/devicescript/blob/main/packages/drivers/src/grovergblcd.ts) is written in TypeScript/DeviceScript.

The sceen is modelled as a [character screen](https://microsoft.github.io/devicescript/developer/graphics/display). Using services allows DeviceScript to provide simulation and device twin capabilities to your coding experience.
 
```ts
import {
    XiaoGroveShield,
    startGroveRGBLCD16x2,
} from "@devicescript/drivers"

const shield = new XiaoGroveShield()
const screen = await startGroveRGBLCD16x2()
await screen.message.write('starting...')
```

## BME680

The [BME680](https://wiki.seeedstudio.com/Grove-Temperature_Humidity_Pressure_Gas_Sensor_BME680/) is a high-precision temperature/humidity/gas sensor that can be conveniently connected through one of the grove connector.

The sensor is exposed as 3 services, temperature, humidity, air quality, that can be used to poll the sensor data and display it on the screen.

```ts
import {
    startBME680,
} from "@devicescript/drivers"

...
const { temperature, humidity } = await startBME680({
    address: 0x76
})
const temp = await temperature.reading.read()
const humi = await humidity.reading.read()
await screen.message.write(`t ${temp}\nh ${humi}`)
```

## Simulation

You try this code without hardware. DeviceScript will spin up simulators for the Xiao, the sensors and screens.

![A screenshot of the simulator view in DeviceScript](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v9i010o1zkfymge6tm8k.png)

## Value dashboard

Since display sensor values is a common task, DeviceScript provides a helper `ValueDashboard` to render a list of sensor data.

The value dashboard

```ts
import { ValueDashboard } from "@devicescript/runtime"

...
const dashboard = new ValueDashboard(screen, {
    temperature: { digits: 1, unit: "C" },
    humi: { digits: 0, unit: "%" },
})

setInterval(async () => {
    dashboard.values.temperature = temperature.reading.read()
    dashboard.values.humi = humidity.reading.read()
    await dashboard.show()
}, 1000)
```

## All together

The final sample is a tiny weather display that shows the temperature/humidity reported by the BME680 sensor.

```ts
import {
    startGroveRGBLCD16x2,
    startBME680,
    XiaoGroveShield,
} from "@devicescript/drivers"
import { ValueDashboard } from "@devicescript/runtime"

const shield = new XiaoGroveShield()
const { temperature, humidity } = await startBME680({
    address: 0x76,
})
const screen = await startGroveRGBLCD16x2()

const dashboard = new ValueDashboard(screen, {
    temp: { digits: 1, unit: "C" },
    humi: { digits: 0, unit: "%" },
})

setInterval(async () => {
    dashboard.values.temp = await temperature.reading.read()
    dashboard.values.humi = await humidity.reading.read()
    await dashboard.show()
}, 1000)
```