Skip to content

A sensor display

Build a three-page touch display: the room's temperature, humidity and pressure with their recent history, and a clock. The flow also publishes the readings over MQTT.

The finished flow is in the Thingstudio repository: test-flows/gui-headliner-sensor-freenove-s3-4in.flow.json. Open it in one of two ways:

  • Open the finished flow. Download it and open it with File → Open…, then set your own WiFi and MQTT credentials in its config nodes.
  • Build it yourself. Follow the steps below.

What you need

The steps use this hardware and setup:

  • A Freenove ESP32-S3 4.0" touch display (FNK0104S), with MicroPython and the runtime installed (Getting started steps 3 to 5). Pick it by hand in the Board menu. Other boards work too; the pins below are this board's.
  • A BME280 sensor board. A BMP280 also works, without humidity. Wire it to 3V3, GND, SCL 15 and SDA 16, the touch panel's I2C bus.
  • A WiFi network for the clock and MQTT, and an MQTT broker. See Connecting over WiFi.

1. Read the sensor

  1. Drag a bme280 onto the canvas. In its I2C bus field, click + and make a bus: bus 0, SCL 15, SDA 16.
  2. Set the bme280's address to 0x76, or 0x77 if your sensor board ties SDO high, and interval (ms) to 5000.
  3. Drag a function node, set outputs to 5, wire the bme280 to it, and use this code:

    p = msg['payload']
    t = {'topic': 'temperature', 'payload': p['temperature']}
    h = None
    if p['humidity'] is not None:   # a BMP280 has no humidity
        h = {'topic': 'humidity', 'payload': p['humidity']}
    pr = {'topic': 'pressure', 'payload': p['pressure']}
    ok = {'topic': 'sensor', 'payload': True}
    return [t, h, pr, pr, ok]
    

    Each reading goes out on its own output, so each widget gets only its own number. Output 4 is a second copy of the pressure, for its journal. Output 5 says the sensor is alive.

To test the sensor first, wire the bme280 to a debug node and deploy. A reading appears every 5 seconds. See bme280.

2. Show it on the display

  1. Drag a display spi onto the canvas and set it for the Freenove panel:

    Property Value
    controller st7796
    frame format rgb565
    SPI bus 1
    baudrate 40000000
    sck, mosi, dc, cs pin 12, 11, 46, 10
    reset pin -1
    backlight pin 45
    width, height 320, 480
    rotation 1
    orientation 90° clockwise
    color order BGR
    invert colors, data latch order on

    Click 💾 to save these as a preset for next time. 2. Drag a gui screen and wire it to the display spi. It takes its width, height and frame format from the display, so the panel's size is set in one place. 3. In the gui screen's touch panel field, click + and make a Touch panel: controller FT6336U, the same I2C bus, address 0x38, width 320, height 480. 4. Drag three gui readout nodes (temperature, humidity, pressure) and a gui light for the sensor. Wire the function's outputs 1, 2, 3 and 5 to them. In each readout, set units, decimals, lowest value and highest value. 5. Lay out the pages: select the gui screen and use the page outline in its properties to add rows of text and readouts. See Laying out pages, and Laying out a display for why the layout is fixed when the flow compiles.

Set stale after on the readouts and the light. A reading that stops arriving is then dimmed, so a dead sensor looks different from a steady room.

3. Add the history

A journal keeps the recent readings, and a gui histogram draws them.

  1. Wire the temperature output to a journal with seconds per row 10, rows kept 156 and rows per roll-up 6. Wire its first output to a gui histogram. That histogram shows the last 26 minutes.
  2. Wire the journal's second output, one summary per minute, to a second journal with seconds per row 0. Wire that journal to a second gui histogram, which shows the last 2.6 hours.
  3. Wire output 4, the pressure copy, to a journal with seconds per row 60, and that to a third gui histogram.

Each bar is the average of its row, and the thin line runs from the row's min to its max. Set each histogram's bottom at and top at to the range you expect, for example 15 to 30 for temperature. A histograms shows only the rows its journal kept: give the journal at least as many rows kept as the histogram has columns, or the bars fill the right of the card and leave the rest empty — the compiler warns with the number to raise. See Histogram.

4. Add the clock

  1. Drag a timer with interval (ms) 1000, and two ntp nodes. Wire the timer to both.
  2. Set one ntp node's format to time and the other's to date. In both, set UTC offset (hours) for your zone's standard time, and daylight saving to UK / EU: automatic if that's where you are, otherwise none. See ntp.
  3. Add two gui label nodes, one for the time with room for (characters) 5, and one for the date with 10. Wire the time ntp node to the first and the date one to the second.
  4. On a new page, give the time label the font font_seg764 (seven-segment digits) and the date font_body24.

Until the board has the time, the labels show --.

5. Turn the pages

Add a gui button with mode navigate to each page, so you can turn the pages by touch. See Buttons.

The example flow also turns the pages every 8 seconds with a gui navigator node, which isn't in the palette. See GUI nodes.

6. Publish the readings

Drag three mqtt publish nodes, one per reading, with topics such as thingstudio/headliner/temperature. Wire outputs 1 to 3 of the function to them, and pick your MQTT broker and WiFi. See mqtt publish.

Deploy

Click Compile → Deploy. The display lights, the readings appear within 5 seconds, the histograms fill as the minutes pass, and the clock starts once the board has the time.

If it doesn't work

Each symptom below has its own fix:

  • The picture is scrambled: the width and height on the display spi must be the panel's own size, 320 and 480, even when the picture is turned; the gui screen follows them. Deploy checks this and says so.
  • Touches land in the wrong place: see Touch panels.
  • No readings: check the wiring and the address (0x76 or 0x77), and test with a debug node.
  • The clock stays at --: the ntp node's status says why: no WiFi yet, or the NTP server can't be reached. It tries again every 30 seconds.
  • Compile says a node is "disconnected from any source": a widget has nothing wired to it. Wire it, or reload the editor if the wires are there.