Hackster will be offline on Monday, June 15 from 5pm to 7pm PDT to perform some scheduled maintenance.
ujjval r.
Created May 17, 2026

Better visualize the heat

A simple real-time heatmap visualization using IR temperature sensor array and LVGL based display interface. Also detect fire incedence.

4
Better visualize the heat

Things used in this project

Hardware components

DFRobot Unihiker K10
×1
Grove - Infrared Temperature Sensor Array (AMG8833)
Seeed Studio Grove - Infrared Temperature Sensor Array (AMG8833)
×1

Software apps and online services

KiCad
KiCad
NextPCB

Story

Read more

Schematics

Schematic of PCB

This is a schematic file. Only schematic related to AMG8833 is relavant for this project.

Code

Final MicroPython code

Python
Follow the connection diagram and then configure the required pins for I2C and you would be good to go
from machine import Pin, I2C
import time
from unihiker_k10 import screen, rgb
import lvgl as lv

# Configure I2C pins and frequency
# Adjust 'scl' and 'sda' pins according to your board
# Example: ESP32 (SCL=22, SDA=21), Raspberry Pi Pico (SCL=1, SDA=0)
i2c = I2C(0, scl=Pin(48), sda=Pin(47), freq=400000)
#Normalmode
i2c.writeto_mem(0x68, 0x00, bytes([0x00]))
time.sleep(0.5)
i2c.writeto_mem(0x68, 0x01, bytes([0x3F]))
time.sleep(0.5)
#10 FPS setting
i2c.writeto_mem(0x68, 0x02, bytes([0x00]))
time.sleep(0.5)

lv.init()
screen.init()

width, height = 8, 8

heatmap_data = [[0 for _ in range(width)] for _ in range(height)]
disp_data = [0 for _ in range(64)]
raws = 8
cols = 8

cell_size = 24

# Create a screen
scr = lv.obj()
lv.init()

canvas = lv.canvas(lv.screen_active())

# Function to map value to LVGL color
def value_to_color_nm(val):
    v = max(0, min(100, val))  # Clamp between 0 and 100
    r = int((v / 100) * 255)
    g = 0
    b = int((1 - v / 100) * 255)
    return r, g, b

while(True):
    data = i2c.readfrom_mem(0x68, 0x80, 128)
    count = 0
    time.sleep(0.2)
    print('\n')
    print('New Frame')
    
    incre = 0
    
    for i in range(0, 127, 2):
        count += 1
        temp = ((data[i+1] << 8 | data[i]) & 0xFFF)        
        if(temp & 0x800):
            temp -= 0x1000
            
        temperature = (temp) * 0.25
        disp_data[incre]=temperature
        incre += 1
        
        print(temperature, end=' ')        
        if (count == 8):
            count = 0
            print() 

    i=0

    max_temp = max(disp_data)
    print(max_temp)
    min_temp = min(disp_data)
    print(max_temp)
    
    for row in range(raws):
        for col in range(cols):            
            r, g, b = value_to_color_nm(disp_data[i])
            i+=1
            x0 = col * cell_size
            y0 = row * cell_size
            screen.draw_rect(x0+20, y0+70, cell_size, cell_size, r << 16 | g << 8 | b, r << 16 | g << 8 | b)
    
    screen.draw_text(text="MAX: "+str(max_temp)+" C",x=20,y=2,font_size=24,color=0xFF0000)
    screen.draw_text(text="MIN: "+str(min_temp)+" C",x=20,y=25,font_size=24,color=0xFF0000)  
    screen.show_draw()
    # Create a screen
    scr = lv.screen_active()
    time.sleep(0.5)
    
    if(max_temp > 50):
        rgb.write(num = 0, R=255,G=0,B=0)
        rgb.write(num = 1, R=255,G=0,B=0)
        rgb.write(num = 2, R=255,G=0,B=0)
    elif(min_temp < 5):
        rgb.write(num = 0, R=0,G=0,B=255)
        rgb.write(num = 1, R=0,G=0,B=255)
        rgb.write(num = 2, R=0,G=0,B=255)
    else:
        rgb.clear()

Zephyr code for nRF52840dk

C/C++
/*
 */

#include <zephyr/device.h>
#include <zephyr/devicetree.h>
#include <zephyr/drivers/display.h>
#include <zephyr/drivers/gpio.h>
#include <lvgl.h>
#include <stdio.h>
#include <string.h>
#include <zephyr/kernel.h>
#include <lvgl_input_device.h>

#include <zephyr/drivers/i2c.h>

#include <math.h>

#define I2C_NODE DT_NODELABEL(i2c1)

// Heatmap dimensions
#define HEATMAP_W  64
#define HEATMAP_H  64

float heatmap_data[64];

#define LOG_LEVEL CONFIG_LOG_DEFAULT_LEVEL
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(app);

// Function to map a value (0..1) to a color
static lv_color_t value_to_color(float value) {
    // Clamp value
    if (value < 0) value = 0;
    if (value > 1) value = 1;

    // Simple gradient: blue -> green -> red
    uint8_t r = (uint8_t)(255 * value);
    uint8_t g = (uint8_t)(255 * (1 - fabs(value - 0.5) * 2));
    uint8_t b = (uint8_t)(255 * (1 - value));

    return lv_color_make(r, g, b);
}
float display_data[HEATMAP_W][HEATMAP_H];
uint8_t add_i = 0, add_j = 0;

void create_heatmap(lv_obj_t *parent) {
    // Allocate buffer for canvas
    static lv_color_t cbuf[HEATMAP_W * HEATMAP_H];

    // Create canvas
    lv_obj_t *canvas = lv_canvas_create(parent);
    lv_canvas_set_buffer(canvas, cbuf, HEATMAP_W, HEATMAP_H, LV_IMG_CF_TRUE_COLOR);
    lv_obj_center(canvas);

	for(int k=0; k<64; k++) {
		for (int i = 0; i < 8; i++) {
			for(int j =0; j < 8; j++) {
				display_data[i+add_i][j+add_j] = heatmap_data[k];
				lv_color_t color = value_to_color(display_data[i+add_i][j+add_j]);
            	lv_canvas_set_px(canvas, i+add_i, j+add_j, color);
				k_sleep(K_MSEC(1));
			}
		}
		add_i += 8;
		if(add_i >= 64) {
			add_i = 0;
			add_j += 8;
		}
	}
}

int main(void)
{
	const struct device *i2c_dev = DEVICE_DT_GET(DT_NODELABEL(i2c1));

	if(!device_is_ready(i2c_dev)) {
		LOG_ERR("Device is not ready:i2c");
		return 0;
	}
	int ret;

	ret = i2c_reg_write_byte(i2c_dev, 0x68, 0x00, 0x00);
	if (ret < 0) {
		LOG_ERR("Failed to write I2C register");
		return 0;
	}

	ret = i2c_reg_write_byte(i2c_dev, 0x68, 0x01, 0x3F);
	if (ret < 0) {
		LOG_ERR("Failed to write I2C register");
		return 0;
	}

	k_sleep(K_MSEC(50));

	ret = i2c_reg_write_byte(i2c_dev, 0x68, 0x02, 0x01);
	if (ret < 0) {
		LOG_ERR("Failed to write I2C register");
		return 0;
	}

	k_sleep(K_MSEC(10));

	uint8_t temp_value[128];
	
	ret = i2c_burst_read(i2c_dev, 0x68, 0x80, temp_value, 128);
	if( ret < 0) {
		LOG_ERR("Failed to read I2C register");
		return 0;
	}

	const struct device *display_dev;

	 /* Create a screen */
    lv_obj_t * scr = lv_scr_act();

    /* Create a heatmap object */

	display_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_display));
	if (!device_is_ready(display_dev)) {
		LOG_ERR("Device not ready, aborting test");
		return 0;
	}
	
	lv_task_handler();
	display_blanking_off(display_dev);

	int j, count;
	int16_t temp;

	while (1) {
		lv_task_handler();		
		k_sleep(K_MSEC(10));
		k_sleep(K_MSEC(1000));

		ret = i2c_burst_read(i2c_dev, 0x68, 0x80, temp_value, 128);

		if( ret < 0) {
			LOG_ERR("Failed to read I2C register");
			return 0;
		}

		k_sleep(K_MSEC(10));
		j = 0;
		count = 0;

		for (int i = 0; i < 127; i++) {
			temp = (((temp_value[i+1] << 8) | temp_value[i]) & 0xFFF);
			if(temp & 0x800) {
				temp = temp - 0x1000;
			}
			heatmap_data[j] = (temp * 0.25)/100.0; // Convert to Celsius and scale
			i = i+1;
			j += 1;
		}

		printf("\n\nNew sample \n ");

		for (int i = 0; i < 64; i++) {
			count++;
			printf("%lf  ", heatmap_data[i]);
			if(count == 8) {
				printf("\n");
				count = 0;
			}			
		}
		k_sleep(K_MSEC(100));
		create_heatmap(scr);
		k_sleep(K_MSEC(2000));
	}
}

Credits

ujjval r.
13 projects • 23 followers

Comments