Migrating a Sensor Library to TuyaOpen
Migrating a sensor library means swapping its bus layer for TuyaOpen's TKL APIs while keeping its register and application logic intact, so the driver runs across every supported platform. This guide ports an existing Arduino or ESP-IDF library.
Prerequisitesโ
- Completed Environment Setup
- Read TDD/TDL Driver Architecture
- An existing sensor library you want to port (Arduino, ESP-IDF, or plain C)
Requirementsโ
- TuyaOpen SDK cloned and environment set up
- Source code of the sensor library
- Sensor datasheet for reference
Migration Strategyโ
Most sensor libraries have three layers:
- Bus abstraction -- Arduino
Wire.hor ESP-IDFi2c_master_* - Register access -- read/write chip registers
- Application logic -- measurement, calibration, conversions
You only need to replace layer 1. Layers 2 and 3 stay the same.
Step-by-Step: Porting a BME280 Arduino Libraryโ
Step 1: Identify the bus callsโ
In a typical Arduino library:
Wire.beginTransmission(addr);
Wire.write(reg);
Wire.endTransmission();
Wire.requestFrom(addr, len);
while (Wire.available()) { data[i++] = Wire.read(); }
Step 2: Create TKL I2C wrappersโ
Replace Wire calls with TuyaOpen equivalents:
#include "tkl_i2c.h"
#define BME280_I2C_PORT TUYA_I2C_NUM_0
#define BME280_ADDR 0x76
static OPERATE_RET bme280_read_reg(UINT8_T reg, UINT8_T *buf, UINT8_T len)
{
OPERATE_RET rt;
rt = tkl_i2c_master_send(BME280_I2C_PORT, BME280_ADDR, ®, 1, FALSE);
if (rt != OPRT_OK) {
return rt;
}
return tkl_i2c_master_receive(BME280_I2C_PORT, BME280_ADDR, buf, len, TRUE);
}
static OPERATE_RET bme280_write_reg(UINT8_T reg, UINT8_T value)
{
UINT8_T buf[2] = { reg, value };
return tkl_i2c_master_send(BME280_I2C_PORT, BME280_ADDR, buf, 2, TRUE);
}
Step 3: Port the init and read functionsโ
Keep the original calibration math. Replace only I/O:
static OPERATE_RET bme280_init(void)
{
UINT8_T chip_id;
OPERATE_RET rt = bme280_read_reg(0xD0, &chip_id, 1);
if (rt != OPRT_OK || chip_id != 0x60) {
return OPRT_COM_ERROR;
}
bme280_write_reg(0xF2, 0x01); /* humidity oversampling x1 */
bme280_write_reg(0xF4, 0x27); /* temp+pressure oversampling x1, normal mode */
bme280_write_reg(0xF5, 0xA0); /* standby 1000ms, filter off */
/* Read calibration data (same logic as Arduino library) */
return bme280_read_calibration();
}
Step 4: Replace delay and print callsโ
| Arduino / ESP-IDF | TuyaOpen |
|---|---|
delay(ms) | tal_system_sleep(ms) |
Serial.println() | TAL_PR_INFO() |
millis() | tal_system_get_millisecond() |
malloc / free | tal_malloc / tal_free |
Step 5: Handle SPI sensorsโ
For SPI sensors, TuyaOpen does not provide a tkl_spi adapter on ESP32. Two options:
Option A: Use ESP-IDF SPI directly (ESP32-only, not portable):
#include "driver/spi_master.h"
spi_device_handle_t spi;
/* Standard ESP-IDF SPI init and transfer */
Option B: Write a thin tkl_spi-like wrapper that you port per platform.
Step 6: Make it a proper TuyaOpen appโ
apps/my_bme280_app/
โโโ CMakeLists.txt
โโโ src/
โ โโโ tuya_main.c
โ โโโ bme280.c
โโโ include/
โ โโโ bme280.h
โโโ config/
โโโ ESP32-S3.config
Common Porting Patternsโ
Arduino Wire.h -> TKL I2Cโ
| Arduino | TuyaOpen |
|---|---|
Wire.begin(sda, scl) | tkl_io_pinmux_config() + tkl_i2c_init() |
Wire.beginTransmission(addr) + Wire.write(data) + Wire.endTransmission() | tkl_i2c_master_send(port, addr, data, len, TRUE) |
Wire.requestFrom(addr, len) + Wire.read() | tkl_i2c_master_receive(port, addr, buf, len, TRUE) |
Wire.setClock(freq) | Set speed in TUYA_IIC_BASE_CFG_T at init |
ESP-IDF i2c_master_* -> TKL I2Cโ
| ESP-IDF | TuyaOpen |
|---|---|
i2c_new_master_bus() | tkl_i2c_init() |
i2c_master_transmit() | tkl_i2c_master_send() |
i2c_master_receive() | tkl_i2c_master_receive() |
i2c_master_bus_rm_device() | tkl_i2c_deinit() |
ESP-IDF gpio_* -> TKL GPIOโ
| ESP-IDF | TuyaOpen |
|---|---|
gpio_config() | tkl_gpio_init() |
gpio_set_level() | tkl_gpio_write() |
gpio_get_level() | tkl_gpio_read() |
gpio_isr_handler_add() | tkl_gpio_irq_init() + tkl_gpio_irq_enable() |
What Cannot Be Ported (Stays Platform-Specific)โ
- DMA-based SPI transfers
- Hardware-specific sensor peripherals (ESP32 touch sensor, ULP ADC)
- Vendor SDK callbacks (
esp_event_*) - FreeRTOS-specific APIs not in TAL (
xEventGroup,xStreamBuffer)