light driver thread implemented

This commit is contained in:
2026-03-19 19:52:13 +01:00
parent 790f537da0
commit 81b589df21
6 changed files with 60 additions and 41 deletions

1
.idea/.name generated
View File

@@ -1 +0,0 @@
st7290

View File

@@ -7,7 +7,6 @@ Generalnie co ma dzialac to juz dziala, thank fuck. Ja pierdole ale api do zigbe
### TODO
- hardware
- weird start up behavior
- wylaczanie lamp nie dziala po gammie
- identyfikacja, niby opcjonalna ale fajny bajer
- factory reset zigbee zeby bylo legitnie, dzwonisz po `esp_zb_factory_reset();`
- status LED zeby bylo legitnie (pokazuje factory reset i OTA kiedys)

View File

@@ -6,7 +6,8 @@ dependencies:
type: local
version: 1.6.8
espressif/cmake_utilities:
component_hash: 351350613ceafba240b761b4ea991e0f231ac7a9f59a9ee901f751bddc0bb18f
component_hash:
351350613ceafba240b761b4ea991e0f231ac7a9f59a9ee901f751bddc0bb18f
dependencies:
- name: idf
require: private
@@ -16,7 +17,8 @@ dependencies:
type: service
version: 0.5.3
espressif/esp-zboss-lib:
component_hash: 321883d142421f65009972408287441794250057668a11abbdfd8bec77c3309a
component_hash:
321883d142421f65009972408287441794250057668a11abbdfd8bec77c3309a
dependencies:
- name: idf
require: private

View File

@@ -8,8 +8,8 @@
#include "esp_err.h"
#include "stdbool.h"
esp_err_t light_driver_init(bool default_state);
esp_err_t light_driver_set_level(uint8_t level, uint16_t transition_ms);
esp_err_t light_driver_set_power(bool power, uint16_t transition_ms);
void light_driver_task(void *pvParameter);
void light_driver_set_level(uint8_t level);
void light_driver_set_power(bool power);
#endif //LIGHT_DRIVER_H

View File

@@ -7,11 +7,12 @@
#include "esp_err.h"
#include <stdbool.h>
#include <math.h>
#include <freertos/semphr.h>
static const char* TAG = "light_driver";
/* tweakable stuff */
static const uint8_t light_gpio = 2;
static const uint8_t light_gpio = 15;
static const uint16_t light_pwm_freq = 65000;
static const ledc_timer_bit_t light_pwm_resolution = LEDC_TIMER_10_BIT;
static const double light_lowest_duty_pct = 0.05; // lowest duty percentage where the LEDs still light up nice
@@ -20,32 +21,27 @@ static const double light_lowest_duty_pct = 0.05; // lowest duty percentage wher
static const ledc_channel_t light_ledc_channel = LEDC_CHANNEL_0;
static const ledc_mode_t light_ledc_speed_mode = LEDC_LOW_SPEED_MODE;
static const uint32_t light_brightness_steps = (1 << light_pwm_resolution) - 1;
SemaphoreHandle_t light_sem = NULL;
/* global vars */
static bool light_init_done = false;
static uint8_t light_current_level = 0;
static uint8_t light_target_level = 0;
static uint16_t gamma_lut[ZIGBEE_LIGHT_LEVELS + 1];
esp_err_t light_driver_set_level(const uint8_t level, const uint16_t transition_ms) {
if (!light_init_done) {
ESP_LOGW(TAG, "light driver not ready!");
return ESP_FAIL;
}
light_current_level = level;
const uint16_t duty = gamma_lut[light_current_level];
ESP_ERROR_CHECK(ledc_fade_stop(light_ledc_speed_mode, light_ledc_channel));
ESP_ERROR_CHECK(ledc_set_fade_with_time(light_ledc_speed_mode, light_ledc_channel, duty, transition_ms));
ESP_ERROR_CHECK(ledc_fade_start(light_ledc_speed_mode, light_ledc_channel, LEDC_FADE_NO_WAIT));
// ESP_LOGI(TAG, "led set to %d, max is %d", duty, light_brightness_steps);
return ESP_OK;
void light_driver_set_level(const uint8_t level) {
xSemaphoreTake(light_sem, portMAX_DELAY);
light_target_level = level;
xSemaphoreGive(light_sem);
}
esp_err_t light_driver_set_power(const bool power, const uint16_t transition_ms) {
return light_driver_set_level(power ? light_current_level : 0, transition_ms);
uint16_t get_level(void) {
xSemaphoreTake(light_sem, portMAX_DELAY);
const uint16_t lvl = light_target_level;
xSemaphoreGive(light_sem);
return MIN(254, lvl);
}
esp_err_t light_driver_init(const bool default_state) {
void light_driver_task(void *pvParameter) {
const ledc_timer_config_t ledc_timer = {
.speed_mode = light_ledc_speed_mode,
.duty_resolution = light_pwm_resolution,
@@ -60,9 +56,14 @@ esp_err_t light_driver_init(const bool default_state) {
.intr_type = LEDC_INTR_DISABLE,
.gpio_num = light_gpio,
.duty = 0, // Set duty to 0%
.hpoint = 0
.hpoint = (int)light_brightness_steps
};
ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer));
ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel));
static uint8_t prev_level = 0;
// pre-compute gamma table
for (uint8_t i = 0; i <= ZIGBEE_LIGHT_LEVELS; i++) {
const double brightness_pct = (double)i / (double)ZIGBEE_LIGHT_LEVELS;
const double gamma_corrected = pow(brightness_pct, 2.2);
@@ -73,11 +74,32 @@ esp_err_t light_driver_init(const bool default_state) {
if (gamma_lut[ZIGBEE_LIGHT_LEVELS] > light_brightness_steps) gamma_lut[ZIGBEE_LIGHT_LEVELS] = light_brightness_steps;
ESP_LOGI(TAG, "pre-computed brightness lookup table");
ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer));
ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel));
ESP_ERROR_CHECK(ledc_fade_func_install(0));
// semaphore init
light_sem = xSemaphoreCreateMutex();
xSemaphoreGive(light_sem);
ESP_LOGI(TAG, "ledc driver initialized, f=%d Hz, %d step resolution", light_pwm_freq, light_brightness_steps);
light_init_done = true;
light_driver_set_power(default_state, 100);
return ESP_OK;
light_driver_set_level(0);
while (true) {
const uint16_t tgt = get_level();
if (tgt != prev_level) {
const int diff = tgt - prev_level;
const int abs_diff = abs(diff);
const int step = MIN(abs_diff / 8 + 1, 20);
if (diff > 0)
prev_level += step;
else
prev_level -= step;
ESP_LOGI(TAG, "setting light level to %d, tgt is %d, step of %d", prev_level, tgt, step);
ledc_set_duty_and_update(light_ledc_speed_mode, light_ledc_channel, gamma_lut[prev_level], light_brightness_steps);
}
vTaskDelay(pdMS_TO_TICKS(20));
}
}
void light_driver_set_power(const bool power) {
light_driver_set_level(power ? get_level() : 0);
}

View File

@@ -12,13 +12,10 @@ static char manufacturer[] = "\x05""Drath";
static char model[] = "\x15""Dimmable Zigbee Light";
static const uint8_t endpoint_no = 1;
static const uint16_t transition_on_off_ms = 500;
static const uint16_t transition_level_ms = 100; // looks like it gets lvl updates from HA every 100ms
static esp_err_t deferred_driver_init(void) {
static bool is_inited = false;
if (!is_inited) {
light_driver_init(LIGHT_DEFAULT_OFF);
xTaskCreate(light_driver_task, "light task", 4096, NULL, 6, NULL);
is_inited = true;
}
return is_inited ? ESP_OK : ESP_FAIL;
@@ -60,7 +57,7 @@ static esp_err_t zigbee_attribute_handler(const esp_zb_zcl_set_attr_value_messag
bool light_state = false;
light_state = message->attribute.data.value ? *(bool*)message->attribute.data.value : light_state;
ESP_LOGI(TAG, "Light sets to %s", light_state ? "On" : "Off");
light_driver_set_power(light_state, transition_on_off_ms);
light_driver_set_power(light_state);
}
break;
@@ -68,7 +65,7 @@ static esp_err_t zigbee_attribute_handler(const esp_zb_zcl_set_attr_value_messag
if (message->attribute.id == ESP_ZB_ZCL_ATTR_LEVEL_CONTROL_CURRENT_LEVEL_ID && message->attribute.data.type == ESP_ZB_ZCL_ATTR_TYPE_U8) {
uint8_t light_level = 0;
light_level = message->attribute.data.value ? *(uint8_t*)message->attribute.data.value : light_level;
light_driver_set_level(light_level, transition_level_ms);
light_driver_set_level(light_level);
ESP_LOGI(TAG, "Light level changes to %d", light_level);
}
break;
@@ -166,9 +163,9 @@ void zigbee_endpoint_init(esp_zb_ep_list_t *ep_list, esp_zb_cluster_list_t *clus
}
/* appearently you cant rename this? */
void esp_zb_app_signal_handler(esp_zb_app_signal_t* signal_struct) {
uint32_t* p_sg_p = signal_struct->p_app_signal;
const esp_err_t err_status = signal_struct->esp_err_status;
void esp_zb_app_signal_handler(const esp_zb_app_signal_t* signal_s) {
uint32_t* p_sg_p = signal_s->p_app_signal;
const esp_err_t err_status = signal_s->esp_err_status;
const esp_zb_app_signal_type_t sig_type = *p_sg_p;
switch (sig_type) {