code enhancements

- add MQTT
- add ESP32-C6
- fix simulation

Signed-off-by: Peter Siegmund <developer@mars3142.org>
This commit is contained in:
2026-03-15 22:41:28 +01:00
parent 5ccc944e30
commit 0869ecc8ce
23 changed files with 373 additions and 139 deletions
+1 -1
View File
@@ -1,2 +1,2 @@
release:
idf.py -B build-release -DSDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.release" fullclean build
idf.py -B build-release -DSDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.release" -DIDF_TARGET=esp32c6 fullclean build size
@@ -15,5 +15,5 @@ idf_component_register(SRCS
simulator
persistence-manager
message-manager
simulator
my_mqtt_client
)
@@ -2,4 +2,4 @@ dependencies:
idf:
version: '>=5.0.0'
espressif/mdns:
version: '*'
version: ^1.10.1
@@ -67,7 +67,7 @@ esp_err_t api_capabilities_get_handler(httpd_req_t *req)
// Thread only available for esp32c6 or esp32h2
bool thread = false;
#if defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32H2)
thread = true;
thread = false;
#endif
cJSON *json = cJSON_CreateObject();
cJSON_AddBoolToObject(json, "thread", thread);
@@ -7,6 +7,7 @@
#include <esp_http_server.h>
#include <esp_log.h>
#include <mdns.h>
#include <sdkconfig.h>
#include <string.h>
static const char *TAG = "api_server";
@@ -55,7 +56,7 @@ static esp_err_t start_webserver(void)
config.server_port = s_config.port;
config.lru_purge_enable = true;
config.max_uri_handlers = 32;
config.max_open_sockets = 7;
config.max_open_sockets = (CONFIG_LWIP_MAX_SOCKETS - 3);
config.uri_match_fn = httpd_uri_match_wildcard;
ESP_LOGI(TAG, "Starting HTTP server on port %d", config.server_port);
@@ -175,6 +176,7 @@ esp_err_t api_server_ws_broadcast_status(bool on, const char *mode, const char *
"{\"type\":\"status\",\"on\":%s,\"mode\":\"%s\",\"schema\":\"%s\","
"\"color\":{\"r\":%d,\"g\":%d,\"b\":%d}}",
on ? "true" : "false", mode, schema, r, g, b);
return api_server_ws_broadcast(buffer);
}
@@ -2,9 +2,10 @@
#include "api_server.h"
#include "common.h"
#include "message_manager.h"
#include "my_mqtt_client.h"
#include <esp_http_server.h>
#include <esp_log.h>
#include <message_manager.h>
#include <string.h>
static const char *TAG = "websocket_handler";
@@ -267,6 +268,8 @@ esp_err_t websocket_broadcast(httpd_handle_t server, const char *message)
}
}
mqtt_publish(message);
return ret;
}
@@ -1,7 +1,4 @@
## IDF Component Manager Manifest File
dependencies:
## Required IDF version
idf:
version: '>=4.1.0'
espressif/ble_conn_mgr: '^0.1.3'
version: '>=5.0.0'
espressif/ble_conn_mgr: '^0.1.6'
@@ -1,2 +1,4 @@
dependencies:
espressif/led_strip: '~3.0.1'
idf:
version: '>=5.0.0'
espressif/led_strip: '~3.0.3'
@@ -103,15 +103,6 @@ static void message_manager_task(void *param)
message_listeners[i](&msg);
}
}
uint8_t mac[6];
esp_read_mac(mac, ESP_MAC_WIFI_STA);
const esp_app_desc_t *app_desc = esp_app_get_description();
char topic[60];
snprintf(topic, sizeof(topic), "device/%s/%02x%02x", app_desc->project_name, mac[4], mac[5]);
char *data = "{\"key\":\"value\"}";
mqtt_client_publish(topic, data, strlen(data), 0, false);
}
}
}
@@ -1,2 +1,5 @@
dependencies:
idf:
version: '>=5.0.0'
espressif/mqtt: ^1.0.0
espressif/cjson: "*"
@@ -3,11 +3,13 @@
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
extern "C"
{
#endif
void mqtt_client_start(void);
void mqtt_client_publish(const char *topic, const char *data, size_t len, int qos, bool retain);
void mqtt_client_start(void);
void mqtt_publish(const char *message);
void mqtt_client_publish(const char *topic, const char *data, size_t len, int qos, bool retain);
#ifdef __cplusplus
}
@@ -8,6 +8,12 @@
#include "mqtt_client.h"
#include "sdkconfig.h"
#include <cJSON.h>
#include <esp_timer.h>
#include <sys/time.h>
#define DEVICE_TOPIC_MAX_LEN 60
static const char *TAG = "mqtt_client";
static esp_mqtt_client_handle_t client = NULL;
@@ -108,12 +114,123 @@ void mqtt_client_start(void)
}
}
void get_device_topic(char *topic, size_t topic_len)
{
uint8_t mac[6];
esp_read_mac(mac, ESP_MAC_WIFI_STA);
const esp_app_desc_t *app_desc = esp_app_get_description();
snprintf(topic, topic_len, "device/%s/%02x%02x", app_desc->project_name, mac[4], mac[5]);
}
void mqtt_publish(const char *message)
{
// Uptime in ms
int64_t uptime_ms = esp_timer_get_time() / 1000;
// UTC time as ISO8601
struct timeval tv;
gettimeofday(&tv, NULL);
struct tm tm_utc;
gmtime_r(&tv.tv_sec, &tm_utc);
char timestamp[32];
strftime(timestamp, sizeof(timestamp), "%Y-%m-%dT%H:%M:%SZ", &tm_utc);
// Firmware version
const esp_app_desc_t *app_desc = esp_app_get_description();
const char *firmware = app_desc->version;
// Reset reason
esp_reset_reason_t reset_reason = esp_reset_reason();
const char *reset_reason_str = "UNKNOWN";
switch (reset_reason)
{
case ESP_RST_POWERON:
reset_reason_str = "POWERON";
break;
case ESP_RST_EXT:
reset_reason_str = "EXT";
break;
case ESP_RST_SW:
reset_reason_str = "SW";
break;
case ESP_RST_PANIC:
reset_reason_str = "PANIC";
break;
case ESP_RST_INT_WDT:
reset_reason_str = "INT_WDT";
break;
case ESP_RST_TASK_WDT:
reset_reason_str = "TASK_WDT";
break;
case ESP_RST_WDT:
reset_reason_str = "WDT";
break;
case ESP_RST_DEEPSLEEP:
reset_reason_str = "DEEPSLEEP";
break;
case ESP_RST_BROWNOUT:
reset_reason_str = "BROWNOUT";
break;
case ESP_RST_SDIO:
reset_reason_str = "SDIO";
break;
default:
break;
}
// Create JSON object
uint8_t mac[6];
esp_read_mac(mac, ESP_MAC_WIFI_STA);
cJSON *root = cJSON_CreateObject();
char mac_str[18];
snprintf(mac_str, sizeof(mac_str), "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
cJSON_AddStringToObject(root, "device_id", mac_str);
cJSON_AddNumberToObject(root, "uptime", uptime_ms);
cJSON_AddStringToObject(root, "timestamp", timestamp);
cJSON_AddStringToObject(root, "firmware", firmware);
cJSON_AddStringToObject(root, "reset_reason", reset_reason_str);
// Insert message as JSON object if possible
char topic_with_type[128];
strncpy(topic_with_type, "", sizeof(topic_with_type));
topic_with_type[sizeof(topic_with_type) - 1] = '\0';
cJSON *msg_obj = cJSON_Parse(message);
if (msg_obj)
{
cJSON *type_item = cJSON_DetachItemFromObject(msg_obj, "type");
if (type_item && cJSON_IsString(type_item))
{
// Extend topic
strncat(topic_with_type, type_item->valuestring, sizeof(topic_with_type) - strlen(topic_with_type) - 1);
}
cJSON_AddItemToObject(root, "message", msg_obj);
cJSON_Delete(type_item); // Free memory
}
else
{
cJSON_AddStringToObject(root, "message", message);
}
// Publish JSON via MQTT
char *json_str = cJSON_PrintUnformatted(root);
mqtt_client_publish(topic_with_type, json_str, strlen(json_str), 0, true);
cJSON_Delete(root);
free(json_str);
}
void mqtt_client_publish(const char *topic, const char *data, size_t len, int qos, bool retain)
{
if (client)
{
int msg_id = esp_mqtt_client_publish(client, topic, data, len, qos, retain);
ESP_LOGI(TAG, "Publish: topic=%s, msg_id=%d, qos=%d, retain=%d, len=%d", topic, msg_id, qos, retain, (int)len);
char base_topic[DEVICE_TOPIC_MAX_LEN];
get_device_topic(base_topic, sizeof(base_topic));
char full_topic[DEVICE_TOPIC_MAX_LEN + 64];
snprintf(full_topic, sizeof(full_topic), "%s/%s", base_topic, topic);
int msg_id = esp_mqtt_client_publish(client, full_topic, data, len, qos, retain);
ESP_LOGV(TAG, "Publish: topic=%s, msg_id=%d, qos=%d, retain=%d, len=%d", full_topic, msg_id, qos, retain,
(int)len);
}
else
{
+76 -95
View File
@@ -4,6 +4,7 @@
#include "led_strip_ws2812.h"
#include "message_manager.h"
#include "persistence_manager.h"
#include "simulator.h"
#include "storage.h"
#include <esp_heap_caps.h>
#include <esp_log.h>
@@ -15,28 +16,7 @@
#include <stdio.h>
#include <string.h>
static const char *TAG = "simulator";
static char *time = NULL;
static char *time_to_string(int hhmm)
{
static char buffer[20];
snprintf(buffer, sizeof(buffer), "%02d:%02d", hhmm / 100, hhmm % 100);
return buffer;
}
static TaskHandle_t simulation_task_handle = NULL;
static SemaphoreHandle_t simulation_mutex = NULL;
static void ensure_mutex_initialized(void)
{
if (simulation_mutex == NULL)
{
simulation_mutex = xSemaphoreCreateMutex();
}
}
// The struct is extended with a 'next' pointer to form a linked list.
// Type definitions
typedef struct light_item_node_t
{
char time[5];
@@ -46,23 +26,42 @@ typedef struct light_item_node_t
struct light_item_node_t *next;
} light_item_node_t;
// Global pointers for the head and tail of the list.
static light_item_node_t *head = NULL;
static light_item_node_t *tail = NULL;
// Interpolation mode selection
typedef enum
{
INTERPOLATION_RGB,
INTERPOLATION_HSV
} interpolation_mode_t;
// You can change this to test different interpolation methods
// Constants and global variables
static const char *TAG = "simulator";
static char *time = NULL;
static TaskHandle_t simulation_task_handle = NULL;
static SemaphoreHandle_t simulation_mutex = NULL;
static light_item_node_t *head = NULL;
static const interpolation_mode_t interpolation_mode = INTERPOLATION_RGB;
char *get_time(void)
// Helper function: converts hhmm format to minutes of the day
static int hhmm_to_minutes(const char time[5])
{
return time;
int t = atoi(time);
return (t / 100) * 60 + (t % 100);
}
// Helper function: converts int hhmm to string
static char *time_to_string(int hhmm)
{
static char buffer[20];
snprintf(buffer, sizeof(buffer), "%02d:%02d", hhmm / 100, hhmm % 100);
return buffer;
}
// Helper function: ensures mutex is initialized
static void ensure_mutex_initialized(void)
{
if (simulation_mutex == NULL)
{
simulation_mutex = xSemaphoreCreateMutex();
}
}
// Main interpolation function that selects the appropriate method
@@ -78,10 +77,11 @@ static rgb_t interpolate_color(rgb_t start, rgb_t end, float factor)
}
}
// Linked list management
esp_err_t add_light_item(const char time[5], uint8_t red, uint8_t green, uint8_t blue, uint8_t white,
uint8_t brightness, uint8_t saturation)
{
// Allocate memory for a new node in PSRAM.
// Allocate memory for new node in PSRAM.
light_item_node_t *new_node = (light_item_node_t *)heap_caps_malloc(sizeof(light_item_node_t), MALLOC_CAP_DEFAULT);
if (new_node == NULL)
{
@@ -106,18 +106,22 @@ esp_err_t add_light_item(const char time[5], uint8_t red, uint8_t green, uint8_t
new_node->blue = (uint8_t)(color.blue * brightness_factor);
new_node->next = NULL;
// Append the new node to the end of the list.
if (head == NULL)
// Insert sorted: find the correct position
if (head == NULL || hhmm_to_minutes(new_node->time) < hhmm_to_minutes(head->time))
{
// If the list is empty, the new node becomes both head and tail.
// New head
new_node->next = head;
head = new_node;
tail = new_node;
}
else
{
// Otherwise, append the new node to the end and update tail.
tail->next = new_node;
tail = new_node;
light_item_node_t *prev = head;
while (prev->next != NULL && hhmm_to_minutes(prev->next->time) < hhmm_to_minutes(new_node->time))
{
prev = prev->next;
}
new_node->next = prev->next;
prev->next = new_node;
}
return ESP_OK;
@@ -136,7 +140,6 @@ void cleanup_light_items(void)
}
head = NULL;
tail = NULL;
ESP_LOGI(TAG, "Cleaned up all light items.");
}
@@ -153,6 +156,8 @@ static void initialize_light_items(void)
load_file(filename);
persistence_manager_deinit(&persistence);
// The list is now sorted because add_light_item inserts sorted
if (head == NULL)
{
ESP_LOGW(TAG, "Light schedule is empty. Simulation will not run.");
@@ -199,43 +204,7 @@ static light_item_node_t *find_best_light_item_for_time(int hhmm)
return best_item;
}
static light_item_node_t *find_next_light_item_for_time(int hhmm)
{
light_item_node_t *current = head;
light_item_node_t *next_item = NULL;
int next_time = 9999; // Initialize with a value larger than any possible time
// First pass: find the soonest time after hhmm
while (current != NULL)
{
int current_time = atoi(current->time);
if (current_time > hhmm && current_time < next_time)
{
next_time = current_time;
next_item = current;
}
current = current->next;
}
// If no item is found for the rest of the day, wrap around to the beginning of the next day
if (next_item == NULL)
{
current = head;
next_time = 9999;
while (current != NULL)
{
int current_time = atoi(current->time);
if (current_time < next_time)
{
next_time = current_time;
next_item = current;
}
current = current->next;
}
}
return next_item;
}
// Messaging
static void send_simulation_message(const char *time, rgb_t color)
{
message_t msg = {};
@@ -247,6 +216,12 @@ static void send_simulation_message(const char *time, rgb_t color)
message_manager_post(&msg, pdMS_TO_TICKS(100));
}
// Public API
char *get_time(void)
{
return time;
}
void start_simulate_day(void)
{
initialize_light_items();
@@ -308,49 +283,55 @@ void simulate_cycle(void *args)
time = time_to_string(hhmm);
light_item_node_t *current_item = find_best_light_item_for_time(hhmm);
light_item_node_t *next_item = find_next_light_item_for_time(hhmm);
light_item_node_t *next_item = NULL;
if (current_item != NULL)
{
rgb_t color = {0, 0, 0};
// Use head as fallback if next_item is NULL
next_item = next_item ? next_item : head;
// Cyclic interpolation: if current_item is the tail element, set next_item to head
if (current_item->next == NULL && head != NULL)
{
next_item = head;
}
else
{
next_item = current_item->next;
}
if (next_item != NULL)
{
int current_item_time_min = (atoi(current_item->time) / 100) * 60 + (atoi(current_item->time) % 100);
int next_item_time_min = (atoi(next_item->time) / 100) * 60 + (atoi(next_item->time) % 100);
int current_minutes = hhmm_to_minutes(current_item->time);
int next_minutes = hhmm_to_minutes(next_item->time);
if (next_item_time_min < current_item_time_min)
// Cyclic transition: if next_minutes < current_minutes, add day length
if (next_minutes < current_minutes)
{
next_item_time_min += total_minutes_in_day;
next_minutes += total_minutes_in_day;
}
int minutes_since_current_item_start = current_minute_of_day - current_item_time_min;
if (minutes_since_current_item_start < 0)
int minutes_since_current = current_minute_of_day - current_minutes;
if (minutes_since_current < 0)
{
minutes_since_current_item_start += total_minutes_in_day;
minutes_since_current += total_minutes_in_day;
}
int interval_duration = next_item_time_min - current_item_time_min;
if (interval_duration == 0)
int interval = next_minutes - current_minutes;
if (interval == 0)
{
interval_duration = 1;
interval = 1;
}
float interpolation_factor = (float)minutes_since_current_item_start / (float)interval_duration;
float factor = (float)minutes_since_current / (float)interval;
// Prepare colors for interpolation
rgb_t start_rgb = {.red = current_item->red, .green = current_item->green, .blue = current_item->blue};
rgb_t end_rgb = {.red = next_item->red, .green = next_item->green, .blue = next_item->blue};
// Use the interpolation function
color = interpolate_color(start_rgb, end_rgb, interpolation_factor);
color = interpolate_color(start_rgb, end_rgb, factor);
led_strip_update(LED_STATE_SIMULATION, color);
}
else
{
// No next_item and no head, use only current
color = (rgb_t){.red = current_item->red, .green = current_item->green, .blue = current_item->blue};
led_strip_update(LED_STATE_SIMULATION, color);
}
@@ -402,7 +383,7 @@ void stop_simulation_task(void)
simulation_task_handle = NULL;
xSemaphoreGive(simulation_mutex);
// Prüfe ob der Task noch existiert bevor er gelöscht wird
// Check if the task still exists before deleting it
eTaskState state = eTaskGetState(handle_to_delete);
if (state != eDeleted && state != eInvalid)
{
+1
View File
@@ -3,6 +3,7 @@ idf_component_register(SRCS
src/app_task.cpp
src/button_handling.c
src/i2c_checker.c
src/u8g2_mqtt.cpp
src/hal/u8g2_esp32_hal.c
INCLUDE_DIRS "include"
PRIV_REQUIRES
+2 -2
View File
@@ -3,5 +3,5 @@ dependencies:
git: https://github.com/olikraus/u8g2.git
# u8g2_hal:
# git: https://github.com/mkfrey/u8g2-hal-esp-idf.git
espressif/button: ^4.1.4
espressif/esp_insights: ^1.2.7
espressif/button: ^4.1.6
espressif/esp_insights: ^1.3.2
+9
View File
@@ -0,0 +1,9 @@
#pragma once
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/task.h"
extern QueueHandle_t display_mqtt_queue;
void u8g2_mqtt_task(void *pvParameters);
+21 -6
View File
@@ -11,6 +11,7 @@
#include "my_mqtt_client.h"
#include "persistence_manager.h"
#include "simulator.h"
#include "u8g2_mqtt.h"
#include "ui/ClockScreenSaver.h"
#include "ui/ScreenSaver.h"
#include "ui/SplashScreen.h"
@@ -33,6 +34,7 @@ u8g2_t u8g2;
uint8_t last_value = 0;
menu_options_t options;
uint8_t received_signal;
uint64_t last_mqtt_sync = 0;
std::shared_ptr<Widget> m_widget;
std::vector<std::shared_ptr<Widget>> m_history;
@@ -148,27 +150,27 @@ static void handle_button(uint8_t button)
{
switch (button)
{
case 1:
case CONFIG_BUTTON_UP:
m_widget->OnButtonClicked(ButtonType::UP);
break;
case 3:
case CONFIG_BUTTON_LEFT:
m_widget->OnButtonClicked(ButtonType::LEFT);
break;
case 5:
case CONFIG_BUTTON_RIGHT:
m_widget->OnButtonClicked(ButtonType::RIGHT);
break;
case 6:
case CONFIG_BUTTON_DOWN:
m_widget->OnButtonClicked(ButtonType::DOWN);
break;
case 16:
case CONFIG_BUTTON_BACK:
m_widget->OnButtonClicked(ButtonType::BACK);
break;
case 18:
case CONFIG_BUTTON_SELECT:
m_widget->OnButtonClicked(ButtonType::SELECT);
break;
@@ -259,6 +261,10 @@ void app_task(void *args)
start_simulation();
display_mqtt_queue = xQueueCreate(1, 1024);
xTaskCreatePinnedToCore(u8g2_mqtt_task, "mqtt_disp", 4096, nullptr, 5, nullptr, tskNO_AFFINITY);
auto oldTime = esp_timer_get_time();
while (true)
@@ -279,6 +285,15 @@ void app_task(void *args)
m_inactivityTracker->update(deltaMs);
}
// MQTT
auto now = esp_timer_get_time();
if (now - last_mqtt_sync > 1000000)
{
uint8_t *u8g2_buf = u8g2_GetBufferPtr(&u8g2);
xQueueOverwrite(display_mqtt_queue, u8g2_buf);
last_mqtt_sync = now;
}
u8g2_SendBuffer(&u8g2);
if (xQueueReceive(buttonQueue, &received_signal, pdMS_TO_TICKS(10)) == pdTRUE)
+23
View File
@@ -5,6 +5,7 @@
#include "persistence_manager.h"
#include "wifi_manager.h"
#include <ble_manager.h>
#include <driver/gpio.h>
#include <esp_event.h>
#include <esp_insights.h>
#include <esp_log.h>
@@ -13,9 +14,31 @@
#include <nvs_flash.h>
#include <sdkconfig.h>
#define WIFI_ENABLE GPIO_NUM_3
#define WIFI_ANT_CONFIG GPIO_NUM_14
__BEGIN_DECLS
void app_main(void)
{
#if defined(CONFIG_IDF_TARGET_ESP32C6)
// GPIO für WiFi Enable konfigurieren
gpio_config_t io_conf = {.pin_bit_mask = (1ULL << WIFI_ENABLE),
.mode = GPIO_MODE_OUTPUT,
.pull_up_en = GPIO_PULLUP_DISABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_DISABLE};
gpio_config(&io_conf);
gpio_set_level(WIFI_ENABLE, 0); // LOW
vTaskDelay(pdMS_TO_TICKS(100));
// GPIO for WiFi antenna configuration
io_conf.pin_bit_mask = (1ULL << WIFI_ANT_CONFIG);
gpio_config(&io_conf);
gpio_set_level(WIFI_ANT_CONFIG, 1); // HIGH
#endif
// Initialize NVS
esp_err_t err = nvs_flash_init();
if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND)
+78
View File
@@ -0,0 +1,78 @@
#include "u8g2_mqtt.h"
#include "esp_timer.h"
#include <my_mqtt_client.h>
#include <stdint.h>
#include <string.h>
#include <u8g2.h>
#define BUFFER_SIZE (128 * 64 / 8)
QueueHandle_t display_mqtt_queue = nullptr;
void u8g2_mqtt_task(void *pvParameters)
{
static uint8_t current_buffer[BUFFER_SIZE];
static uint8_t previous_buffer[BUFFER_SIZE] = {0};
static uint8_t mqtt_payload[BUFFER_SIZE * 2 + 1];
uint64_t last_keyframe_time = 0;
const uint64_t KEYFRAME_INTERVAL_US = 5000000; // 5 seconds in microseconds
while (true)
{
// Blocks without CPU load until app_task provides a frame
if (xQueueReceive(display_mqtt_queue, current_buffer, portMAX_DELAY) == pdTRUE)
{
int payload_size = 0;
uint64_t current_time = esp_timer_get_time();
// Time-based I-frame decision (or on initial start)
bool is_keyframe = (current_time - last_keyframe_time >= KEYFRAME_INTERVAL_US) || (last_keyframe_time == 0);
if (is_keyframe)
{
mqtt_payload[payload_size++] = 0x01; // Header: I-frame
last_keyframe_time = current_time;
for (int i = 0; i < BUFFER_SIZE;)
{
uint8_t count = 1;
while (i + count < BUFFER_SIZE && current_buffer[i] == current_buffer[i + count] && count < 255)
{
count++;
}
mqtt_payload[payload_size++] = count;
mqtt_payload[payload_size++] = current_buffer[i];
i += count;
}
}
else
{
mqtt_payload[payload_size++] = 0x00; // Header: P-frame (Diff)
uint8_t xor_buffer[BUFFER_SIZE];
for (int i = 0; i < BUFFER_SIZE; i++)
{
xor_buffer[i] = current_buffer[i] ^ previous_buffer[i];
}
for (int i = 0; i < BUFFER_SIZE;)
{
uint8_t count = 1;
while (i + count < BUFFER_SIZE && xor_buffer[i] == xor_buffer[i + count] && count < 255)
{
count++;
}
mqtt_payload[payload_size++] = count;
mqtt_payload[payload_size++] = xor_buffer[i];
i += count;
}
}
// --- MQTT SEND ---
mqtt_client_publish("stream", (char *)mqtt_payload, payload_size, 0, false);
memcpy(previous_buffer, current_buffer, BUFFER_SIZE);
}
}
}
+15 -8
View File
@@ -4,17 +4,24 @@ CONFIG_IDF_TARGET="esp32c6"
#
# Display Settings
#
CONFIG_DISPLAY_SDA_PIN=9
CONFIG_DISPLAY_SCL_PIN=8
CONFIG_DISPLAY_SDA_PIN=22
CONFIG_DISPLAY_SCL_PIN=23
# end of Display Settings
#
# Button Configuration
#
CONFIG_BUTTON_UP=7
CONFIG_BUTTON_DOWN=4
CONFIG_BUTTON_LEFT=6
CONFIG_BUTTON_RIGHT=5
CONFIG_BUTTON_SELECT=19
CONFIG_BUTTON_BACK=20
CONFIG_BUTTON_UP=18
CONFIG_BUTTON_DOWN=17
CONFIG_BUTTON_LEFT=20
CONFIG_BUTTON_RIGHT=19
CONFIG_BUTTON_SELECT=1
CONFIG_BUTTON_BACK=2
# end of Button Configuration
CONFIG_WLED_DIN_PIN=21
CONFIG_STATUS_WLED_PIN=16
CONFIG_API_SERVER_HOSTNAME="system-control"
CONFIG_LWIP_MAX_SOCKETS=20
+2
View File
@@ -1,2 +1,4 @@
# default ESP target
CONFIG_IDF_TARGET="esp32s3"
CONFIG_API_SERVER_HOSTNAME="system-client"
+2
View File
@@ -3,4 +3,6 @@ CONFIG_APP_REPRODUCIBLE_BUILD=y
# Compiler options
CONFIG_COMPILER_OPTIMIZATION_PERF=y
# CONFIG_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE=y
CONFIG_DEBUG_INFO=n
+1 -2
View File
@@ -46,8 +46,7 @@
</div>
<div class="btn-group">
<button class="btn btn-primary" id="connect-btn" onclick="saveWifi()" data-i18n="captive.connect"
disabled>
<button class="btn btn-primary" id="connect-btn" onclick="saveWifi()" data-i18n="captive.connect">
💾 Verbinden
</button>
</div>