257 views|0 replies

10

Posts

1

Resources
The OP
 

【2024 DigiKey Innovation Competition】Smart Home Control Center [Copy link]

 This post was last edited by Netseye on 2024-10-28 12:52

1. Introduction

This work uses ESP32-S3-LCD-EV-BOARD and STEMMA QT BME680 SENSOR BOARD BME680 to implement some attempts related to smart home.

The main function is to implement esp-rainmaker QR code network configuration based on ESP32-S3-LCD-EV-BOARD.

The indoor gas, humidity, pressure and temperature data are obtained through bme680 and displayed on the screen. And synchronized to ESP RAINMAKER at regular intervals . When the temperature of bme680 exceeds 30, a high temperature warning notification will be sent through esp-rainker.

And data reporting is realized through esp-rainker. If the temperature of bme680 exceeds 30, a high temperature warning notification will be sent through esp-rainker.

The outdoor temperature can be obtained through the network and displayed on the screen. The lights can be turned on and off by voice commands. The indoor temperature and humidity cycle

2. System Block Diagram

File Directory

3185   tree -L 2
.
├── CMakeLists.txt
├── README.md
├── bsp                             
│   └── bsp_extra                   // esp32 bsp extra
├── components                      
│   ├── app_insights                // ESP Insights (Beta)
│   ├── app_network                 // 网络配置相关库
│   ├── app_reset                   // 重置相关库提供给esp-rmaker使用
│   ├── bme68x_lib                  // BME68X传感器驱动
│   ├── gpio_button                 // 按键驱动
│   ├── i2c_bus                     // I2C总线驱动
│   ├── nimble_central_utils        // NimBLE工具库
│   └── qrcode                      // 二维码库
├── dependencies.lock
├── esp_tts_voice_data_xiaoxin.dat  // tts语音数据
├── main                            // 项目主目录
│   ├── CMakeLists.txt
│   ├── Kconfig
│   ├── app                         // 项目应用层逻辑代码
│   ├── gui                         // 项目GUI代码  
│   ├── idf_component.yml           // 项目组件依赖配置
│   ├── main.c                      // 项目入口 
│   ├── main.h                      
│   ├── rmaker                       // esp-rmaker相关代码
│   ├── settings.c                   // 项目配置   
│   └── settings.h
├── partitions.csv                  // 分区表
├── sdkconfig
├── sdkconfig.defaults
├── sdkconfig.defaults.psram_120m_ddr
├── sdkconfig.old
└── spiffs                           // spiffs文件系统存音频文件和图片
    ├── echo_cn_end.wav
    ├── echo_cn_ok.wav
    ├── echo_cn_wake.wav
    ├── echo_en_end.wav
    ├── echo_en_ok.wav
    ├── echo_en_wake.wav
    ├── gpt_avatar.gif
    └── mp3

18 directories, 23 files

Core code

3193   tree -L 2

.
├── CMakeLists.txt
├── Kconfig
├── app
│   ├── app_audio.c
│   ├── app_audio.h
│   ├── app_ble.c
│   ├── app_ble.h
│   ├── app_chat.c
│   ├── app_chat.h
│   ├── app_sr.c
│   ├── app_sr.h
│   ├── app_sr_handler.c
│   ├── app_sr_handler.h
│   ├── app_sr_tts.c
│   ├── app_sr_tts.h
│   ├── app_weather.c
│   ├── app_weather.h
│   └── blecent.h
├── gui
│   ├── assert
│   ├── font
│   ├── lv_example_image.h
│   ├── lv_example_pub.c
│   ├── lv_example_pub.h
│   ├── lv_example_top_menu.c
│   ├── lv_schedule_basic.c
│   ├── lv_schedule_basic.h
│   ├── ui_chat.c
│   ├── ui_chat.h
│   ├── ui_rmaker.c
│   ├── ui_rmaker.h
│   ├── ui_sr.c
│   └── ui_sr.h
├── idf_component.yml
├── main.c
├── main.h
├── rmaker
│   ├── app_bme680.c
│   ├── app_bme680.h
│   ├── app_driver.c
│   ├── app_priv.h
│   ├── app_rmaker.c
│   └── app_rmaker.h
├── settings.c
└── settings.h

3. Functional description of each part

Main


void app_main(void)
{
    /* Initialize NVS. */
    esp_err_t err = nvs_flash_init();
    if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
        ESP_ERROR_CHECK(nvs_flash_erase());
        err = nvs_flash_init();
    }
    ESP_ERROR_CHECK(err);
    ESP_ERROR_CHECK(settings_read_parameter_from_nvs());

    bsp_spiffs_mount();

    bsp_i2c_init();
    bsp_display_start();
    bsp_extra_led_init();
    bsp_extra_codec_init();

    app_bme680_init();

    ESP_LOGI(TAG, "Display LVGL");
    bsp_display_lock(0);
    
    lv_style_pre_init();
    lv_create_home(&rmaker_Layer);

    bsp_display_unlock();
    ESP_LOGI(TAG, "Initializing RainMaker");
    app_rmaker_start();

    app_weather_start();

    ESP_LOGI(TAG, "speech recognition Enable");
    app_sr_start(false);
    bsp_audio_poweramp_enable(true);

    ESP_LOGI(TAG, "TTS Enable");
    app_tts_init();
}

BME680 Data Collection

// 初始化i2c bme680
void app_bme680_init(void) {
  // 初始化 I2C 总线
  esp_err_t ret = i2c_bus_init(
      &i2c_bus, BSP_I2C_NUM, BSP_I2C_SDA_R16, BSP_I2C_SCL_R16,
      GPIO_PULLUP_DISABLE, GPIO_PULLUP_DISABLE, CONFIG_BSP_I2C_CLK_SPEED_HZ);

  // 初始化 bme68x_lib_t 实例
  esp_err_t result = bme68x_lib_init(&bme68x_instance, &i2c_bus, intf);
  if (result != ESP_OK) {
    ESP_LOGE(TAG, "BME680 initialization failed");
  } else {
    ESP_LOGI(TAG, "BME680 initialized successfully");
  }

  bme68x_lib_set_filter(&bme68x_instance, BME68X_FILTER_OFF);
  bme68x_lib_set_tph(&bme68x_instance, BME68X_OS_2X, BME68X_OS_1X,
                     BME68X_OS_16X);
  bme68x_lib_set_heater_prof_for(&bme68x_instance, 300, 100);
  bme68x_lib_set_op_mode(&bme68x_instance, ope_mode);
}

// 获取bme680信息
esp_err_t app_bme680_get_current_info(bme68x_data_t *info) {

  if (bme68x_lib_intf_error(&bme68x_instance) == 0) {
    bme68x_lib_set_op_mode(&bme68x_instance, ope_mode);
    bme_delay = bme68x_lib_get_meas_dur(&bme68x_instance, ope_mode);
    (bme68x_instance.bme6).delay_us(bme_delay, (bme68x_instance.bme6).intf_ptr);

    bme68x_lib_fetch_data(&bme68x_instance);
    bme68x_data_t *data = bme68x_lib_get_all_data(&bme68x_instance);

    info->temperature = data->temperature;
    info->pressure = data->pressure;
    info->humidity = data->humidity;
    info->gas_resistance = data->gas_resistance;
    info->status = data->status;

    return ESP_OK;
  } else {
    return ESP_FAIL;
  }
}

链接已隐藏,如需查看请登录或者注册

 /* Create a Switch device and add the relevant parameters to it */
  switch_device =
      esp_rmaker_switch_device_create("开关", NULL, DEFAULT_SWITCH_POWER);
  esp_rmaker_device_add_cb(switch_device, write_cb, NULL);
  esp_rmaker_node_add_device(node, switch_device);

  /* Create a Light device and add the relevant parameters to it */
  light_device =
      esp_rmaker_lightbulb_device_create("灯", NULL, DEFAULT_LIGHT_POWER);
  esp_rmaker_device_add_cb(light_device, write_cb, NULL);

  esp_rmaker_device_add_param(light_device, esp_rmaker_brightness_param_create(
                                                ESP_RMAKER_DEF_BRIGHTNESS_NAME,
                                                DEFAULT_LIGHT_BRIGHTNESS));

  esp_rmaker_param_t *color_param = esp_rmaker_param_create("color", NULL, esp_rmaker_int(0), PROP_FLAG_READ | PROP_FLAG_WRITE);
  esp_rmaker_param_add_ui_type(color_param, ESP_RMAKER_UI_HUE_SLIDER);
  esp_rmaker_device_add_param(light_device, color_param);

  esp_rmaker_device_add_attribute(light_device, "Desc", "2024 DigiKey");

  esp_rmaker_node_add_device(node, light_device);

  /* Create a Fan device and add the relevant parameters to it */
  fan_device = esp_rmaker_fan_device_create("风扇", NULL, DEFAULT_FAN_POWER);
  esp_rmaker_device_add_cb(fan_device, write_cb, NULL);
  esp_rmaker_device_add_param(fan_device,
  esp_rmaker_speed_param_create(ESP_RMAKER_DEF_SPEED_NAME,
  DEFAULT_FAN_SPEED)); esp_rmaker_node_add_device(node, fan_device);

  //2 节点上: 创建一个BME680设备。
  temp_sensor_device = esp_rmaker_temp_sensor_device_create("BME680", NULL, 0); 

  // // 接下来的几行代码创建了几个参数,如“地区”、“天气”、“风力”和“湿度”,并设置了它们的属性和初始值。
  esp_rmaker_param_t *temperature_param = esp_rmaker_param_create("温度", "bme680.param.temperature",  esp_rmaker_float(app_get_current_temperature()), PROP_FLAG_READ | PROP_FLAG_WRITE);
  esp_rmaker_param_t *humidity_param = esp_rmaker_param_create("湿度", "bme680.param.humidity", esp_rmaker_float(app_get_current_humidity()), PROP_FLAG_READ | PROP_FLAG_WRITE);
  esp_rmaker_param_t *pressure_param = esp_rmaker_param_create("气压", "bme680.param.pressure", esp_rmaker_float(app_get_current_pressure()), PROP_FLAG_READ | PROP_FLAG_WRITE);
  esp_rmaker_param_t *altitude_param = esp_rmaker_param_create("海拔", "bme680.param.altitude", esp_rmaker_float(app_get_current_altitude()), PROP_FLAG_READ | PROP_FLAG_WRITE);
  esp_rmaker_param_t *gas_param = esp_rmaker_param_create("GAS", "bme680.param.gas", esp_rmaker_float(app_get_current_gas()), PROP_FLAG_READ | PROP_FLAG_WRITE);
  esp_rmaker_param_t *iaq_param = esp_rmaker_param_create("IAQ", "bme680.param.iaq", esp_rmaker_float(app_get_current_iaq()), PROP_FLAG_READ | PROP_FLAG_WRITE);

  // // 这些参数随后被添加到温度传感器虚拟设备中。
  esp_rmaker_device_add_param(temp_sensor_device, temperature_param);
  esp_rmaker_device_add_param(temp_sensor_device, humidity_param);
  esp_rmaker_device_add_param(temp_sensor_device, pressure_param);
  esp_rmaker_device_add_param(temp_sensor_device, altitude_param);
  esp_rmaker_device_add_param(temp_sensor_device, gas_param);
  esp_rmaker_device_add_param(temp_sensor_device, iaq_param);

  // // 设置主要参数 app上首先显示
  esp_rmaker_device_assign_primary_param(temp_sensor_device, temperature_param);

  // esp_rmaker_param_t *get_param = esp_rmaker_param_create("get_weather", NULL, esp_rmaker_bool(false), PROP_FLAG_READ | PROP_FLAG_WRITE);
  // esp_rmaker_param_add_ui_type(get_param, ESP_RMAKER_UI_PUSHBUTTON);
  // esp_rmaker_device_add_param(temp_sensor_device, get_param);

  esp_rmaker_node_add_device(node, temp_sensor_device);

Esp-sr

Command List

static const sr_cmd_t g_default_cmd_info[] = {
    // Chinese
    {SR_CMD_TEMP_DEC, SR_LANG_CN, 0, "室内温度", "shi nei wen du", {NULL}},
    {SR_CMD_PRESSURE_DEC, SR_LANG_CN, 0, "室内气压", "shi nei qi ya", {NULL}},
    {SR_CMD_HUMIDITY_DEC, SR_LANG_CN, 0, "室内湿度", "shi nei shi du", {NULL}},

    {SR_CMD_LIGHT_ON, SR_LANG_CN, 0, "打开电灯", "da kai dian deng", {NULL}},
    {SR_CMD_LIGHT_OFF, SR_LANG_CN, 0, "关闭电灯", "guan bi dian deng", {NULL}},
};

Esp-sr initialization

    BaseType_t ret_val;

    models = esp_srmodel_init("model");
    afe_handle = (esp_afe_sr_iface_t *)&ESP_AFE_SR_HANDLE;
    afe_config_t afe_config = AFE_CONFIG_DEFAULT();

    afe_config.wakenet_model_name = esp_srmodel_filter(models, ESP_WN_PREFIX, NULL);
    afe_config.aec_init = false;

    esp_afe_sr_data_t *afe_data = afe_handle->create_from_config(&afe_config);
    g_sr_data->afe_handle = afe_handle;
    g_sr_data->afe_data = afe_data;

    sys_param_t *param = settings_get_parameter();
    g_sr_data->lang = SR_LANG_MAX;
    ret = app_sr_set_language(param->sr_lang);

esp-sr handler



void sr_handler_task(void *pvParam)
{
    static lv_event_info_t event;
    event.event = LV_EVENT_EXIT_CLOCK;

    while (true) {
        sr_result_t result;
        app_sr_get_result(&result, portMAX_DELAY);

        if (true == result.beep_enable) {
            sr_echo_play(AUDIO_PRESS);
            continue;
        }

        if (ESP_MN_STATE_TIMEOUT == result.state) {
#if !SR_RUN_TEST
            event.event = LV_EVENT_I_AM_LEAVING;
            app_lvgl_send_event(&event);
            sr_echo_play(AUDIO_END);
#endif
            continue;
        }

        if (WAKENET_DETECTED == result.wakenet_mode) {
            event.event = LV_EVENT_I_AM_HERE;
            app_lvgl_send_event(&event);
#if !SR_RUN_TEST
            sr_echo_play(AUDIO_WAKE);
#endif
            continue;
        }

        if (ESP_MN_STATE_DETECTED & result.state) {
            const sr_cmd_t *cmd = app_sr_get_cmd_from_id(result.command_id);
            if (NULL == cmd) {
                continue;
            }

            ESP_LOGI(TAG, "command:%s, act:%d", cmd->str, cmd->cmd);
            event.event_data = (void *)cmd->str;

            switch (cmd->cmd) {
            case SR_CMD_SET_RED:
                event.event = LV_EVENT_LIGHT_RGB_SET;
                app_lvgl_send_event(&event);
                break;
            case SR_CMD_SET_WHITE:
                event.event = LV_EVENT_LIGHT_RGB_SET;
                app_lvgl_send_event(&event);
                break;
            case SR_CMD_SET_YELLOW:
                event.event = LV_EVENT_LIGHT_RGB_SET;
                app_lvgl_send_event(&event);
                break;
            case SR_CMD_SET_BLUE:
                event.event = LV_EVENT_LIGHT_RGB_SET;
                app_lvgl_send_event(&event);
                break;
            case SR_CMD_LIGHT_ON:
                event.event = LV_EVENT_LIGHT_ON;
                app_lvgl_send_event(&event);
                break;
            case SR_CMD_LIGHT_OFF:
                event.event = LV_EVENT_LIGHT_OFF;
                app_lvgl_send_event(&event);
                break;
            case SR_CMD_TEMP_DEC:

                char temp_str[64];
                snprintf(temp_str, sizeof(temp_str), "室内当前 %.2f  摄氏度  ", info.temperature);
                app_tts_play(temp_str);

                break;
            case SR_CMD_PRESSURE_DEC:
                char pressure_str[64];
                snprintf(pressure_str, sizeof(pressure_str), "室内当前 %.2f  千帕  ", info.pressure / 100.0);
                app_tts_play(pressure_str);
                break;
            case SR_CMD_HUMIDITY_DEC:
                char humidity_str[64];
                snprintf(humidity_str, sizeof(humidity_str), "室内当前湿度 %.2f ", info.humidity);
                app_tts_play(humidity_str);
                break;

            default:
                ESP_LOGE(TAG, "Unknow cmd");
                break;
            }
#if !SR_RUN_TEST
            // sr_echo_play(AUDIO_OK);
#endif
        }
    }
    vTaskDelete(NULL);
}

Esp-tts


esp_err_t app_tts_init(void) {
    /* Initial voice set from separate voice data partition */
    const esp_partition_t* part = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "voice_data");

    if (part==NULL) { 
        ESP_LOGE(TAG, "Couldn't find voice data partition!");
        return 0;
    } else {
        ESP_LOGI(TAG, "voice_data paration size:%ld", part->size);
    }

    const void* voicedata;

    esp_partition_mmap_handle_t mmap;
    esp_err_t err = esp_partition_mmap(part, 0, part->size, ESP_PARTITION_MMAP_DATA, &voicedata, &mmap);

    if (err != ESP_OK) {
        ESP_LOGE(TAG, "Couldn't map voice data partition!");
        return ESP_FAIL;
    }

    esp_tts_voice_t *voice = esp_tts_voice_set_init(&esp_tts_voice_template, (int16_t*)voicedata); 

    tts_handle = esp_tts_create(voice);
    if (tts_handle == NULL) {
        ESP_LOGE(TAG, "Failed to create TTS handle!");
        return ESP_FAIL;
    }

    spk_codec_dev = bsp_audio_codec_speaker_init();
    assert(spk_codec_dev);
    esp_codec_dev_set_out_vol(spk_codec_dev, DEFAULT_VOLUME);

    return ESP_OK;
}

esp_err_t app_tts_play(const char *prompt1)
{
    esp_codec_dev_sample_info_t fs = {
        .sample_rate        = SAMPLE_RATE,
        .channel            = EXAMPLE_CHANNEL,
        .bits_per_sample    = EXAMPLE_BITS,
    };
    esp_codec_dev_open(spk_codec_dev, &fs);

    /* Play prompt text */
    ESP_LOGI(TAG, "prompt1: %s", prompt1);
    if (esp_tts_parse_chinese(tts_handle, prompt1)) {
            int len[1]={0};
            do {
                short *pcm_data=esp_tts_stream_play(tts_handle, len, 1);
                int error_code = esp_codec_dev_write(spk_codec_dev, pcm_data, len[0]*2);
                // ESP_LOGI(TAG, "Write result: %d ", error_code);
                // ESP_LOGI(TAG, "data: %d", len[0]);
            } while(len[0]>0);
    }

    esp_codec_dev_close(spk_codec_dev);

    esp_tts_stream_reset(tts_handle);

    return ESP_OK;
}

4. Source Code

iot-box.zip

5. Demonstration video of the work’s functions

10月28日

6. Project Summary

https://en.eeworld.com/bbs/thread-1291239-1-1.html

https://en.eeworld.com/bbs/thread-1292908-1-1.html

https://en.eeworld.com/bbs/thread-1296188-1-1.html

ESP32-S3-LCD-EV-BOARD and bme680 are excellent development boards and sensors. This project is just a starting point for exploring IoT under the Espressif ecosystem, and it does not fully demonstrate its application in IoT. The original plan was to have corresponding LLM large model dialogue and BLE to connect Xiaomi Bluetooth devices. There were some performance and conflict issues during the trial process. They have not been resolved yet. The debugging process is painful. It takes several minutes to completely flash the firmware...

VII. Others

The code will be optimized and organized later to solve the integration problems of large model dialogue and BLE access to Mijia devices, making the project more perfect.

This post is from DigiKey Technology Zone
 
 

Guess Your Favourite
Just looking around
Find a datasheet?

EEWorld Datasheet Technical Support

Featured Posts
MATLAB APP Designer serial port debugging tool writing

This post was last edited by lb8820265 on 2019-5-9 23:11 Previously, we introduced two ways to use VC6 to make serial ...

About the original picture and packaging

Does anyone have the original picture and package of STM32F103 series?

How to use CPLD to collect asynchronous signals

Scenario: Use CPLD to decode a serial data channel. The data has no accompanying clock and has a fixed frequency but a d ...

Measuring poles and zeros from a Bode plot

This post was last edited by Jack315 on 2021-1-25 00:52 The transfer function of a single zero is: 522846 The Bode plot ...

Encoder counting principle and motor speed measurement principle - multi-picture analysis

This post was last edited by DDZZ669 on 2021-2-14 23:30 Encoder is a sensor used to measure mechanical rotation or displ ...

35 "Ten Thousand Miles" Raspberry Pi Car——ROS Learning (Realizing Hello World)

The best way to learn ROS is to use it. The ROS official website has a Chinese version of the tutorial . After install ...

36 "Ten Thousand Miles" Raspberry Pi Car——ROS Learning (VSCode to Implement Hello World)

It is very convenient to run ROS projects in VSCode. In this section, we use ROS to write and run the "Hello world" pro ...

[The strongest open source] Hand-rubbed 120W switching power supply

I recently took the time to make a switching power supply 645265 645262 645263 645264 645261 645260

Record a blue screen pit

I mentioned a while ago that my company's computers would occasionally blue screen. Now I think about it, the blue scree ...

ESP8266 01+DHT11 acquisition

Could anyone give me some advice? When I collect DHT11 data through one of GPIO 0 and 2, the 8266 01 keeps restarting. O ...

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号
快速回复 返回顶部 Return list