Skip to main content

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โ€‹

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:

  1. Bus abstraction -- Arduino Wire.h or ESP-IDF i2c_master_*
  2. Register access -- read/write chip registers
  3. 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, &reg, 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-IDFTuyaOpen
delay(ms)tal_system_sleep(ms)
Serial.println()TAL_PR_INFO()
millis()tal_system_get_millisecond()
malloc / freetal_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โ€‹

ArduinoTuyaOpen
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-IDFTuyaOpen
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-IDFTuyaOpen
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)

Referencesโ€‹