ESP32-S3-BOX-3
-
- Pokročilý
- Příspěvky: 170
- Registrován: 13. červenec 2023, 16:04
- Dal poděkování: 12 poděkování
- Dostal poděkování: 3 poděkování
Re: ESP32-S3-BOX-3
Tak to je pak jasne.
Ja jsem teda puvodne reagoval hlavne v kontextu tohohle esp32-s3-box-3. Ma dost vykonu na to, aby tenhle filr udelal sam? Jak pozici tech zdroju kalibrujes? atd.
Ja jsem teda puvodne reagoval hlavne v kontextu tohohle esp32-s3-box-3. Ma dost vykonu na to, aby tenhle filr udelal sam? Jak pozici tech zdroju kalibrujes? atd.
-
- Moderátor
- Příspěvky: 739
- Registrován: 03. červenec 2021, 18:35
- Dal poděkování: 84 poděkování
- Dostal poděkování: 175 poděkování
Re: ESP32-S3-BOX-3
Podle reálného chování s tím něco v té esp-adf/esp-dsp dělá. Na porovnání mám jednomikrofon, ReSpeaker (zatím ne na ESP32, ale v RPi satelitu) a možná ještě objednám třímikrofon ESP32-S3-Korvo-1
Vše co si přinesu domů je buď Shelly, nebo to skončí buď pod ESPhome nebo pod Zigbee2mqtt.
Ajťák co pamatuje BBS a OS/2 Warp a je mu jedno o jaký systém nebo síťařinu běží.
HA OS jako jedna z Proxmox VM na Odroid H3+/64GB https://github.com/tteck/Proxmox
Ajťák co pamatuje BBS a OS/2 Warp a je mu jedno o jaký systém nebo síťařinu běží.
HA OS jako jedna z Proxmox VM na Odroid H3+/64GB https://github.com/tteck/Proxmox
- Pete30
- Moderátor
- Příspěvky: 2901
- Registrován: 30. září 2020, 20:33
- Dal poděkování: 152 poděkování
- Dostal poděkování: 319 poděkování
Re: ESP32-S3-BOX-3
Na esphome je nový fw pro esp32-s3-box 3, nezkoušel to někdo ?
https://github.com/esphome/firmware/blo ... box-3.yaml
Zatím si myslím že co máme zde bude lepší i když jsem se k tomu ještě nedostal (už ho mám doma), ale zatím ještě dodělávám openhasp display.
https://github.com/esphome/firmware/blo ... box-3.yaml
Zatím si myslím že co máme zde bude lepší i když jsem se k tomu ještě nedostal (už ho mám doma), ale zatím ještě dodělávám openhasp display.
Pokud nejsem přítomen tak jsem na rybách 

-
- Moderátor
- Příspěvky: 739
- Registrován: 03. červenec 2021, 18:35
- Dal poděkování: 84 poděkování
- Dostal poděkování: 175 poděkování
Re: ESP32-S3-BOX-3
Díky za odkaz, už konečně vím jak podstrčit custom audio board.
Jak jsem psal - já nakonec po neúspěšných pokusech šel cestou redefinice GPIO u s3-box.
Trochu jsem doufal že Jesse už to má rozjeté proti aktuální verzi ESP-ADF/ESP-IDF ale v tom branchi žádnou aktivitu nevidím (https://github.com/esphome/esphome/tree ... 3-284-v2.6)
Aktuálně je jedno kterou verzi použijete.
Rozdíly jsou v omáčce kolem:
Jesse má taktovanou PSRAM na 80MHz a obrázky na displeji,
Já na rychlejších 120MHz (S3-box-3 to oficiálně umí) a výpis událostí.
Nebo kombinujte a tvořte vlastní...
V příští verzi yaml co sem dám bude lepší výpis událostí a pravděpodobně se odkážu s definicí desky také do Jesseho repa https://github.com/jesserockz/esp32-s3-box-3-board ať to v případě budoucích změn nemusím udržovat duplicitní.
Jak jsem psal - já nakonec po neúspěšných pokusech šel cestou redefinice GPIO u s3-box.
Trochu jsem doufal že Jesse už to má rozjeté proti aktuální verzi ESP-ADF/ESP-IDF ale v tom branchi žádnou aktivitu nevidím (https://github.com/esphome/esphome/tree ... 3-284-v2.6)
Aktuálně je jedno kterou verzi použijete.
Rozdíly jsou v omáčce kolem:
Jesse má taktovanou PSRAM na 80MHz a obrázky na displeji,
Já na rychlejších 120MHz (S3-box-3 to oficiálně umí) a výpis událostí.
Nebo kombinujte a tvořte vlastní...
V příští verzi yaml co sem dám bude lepší výpis událostí a pravděpodobně se odkážu s definicí desky také do Jesseho repa https://github.com/jesserockz/esp32-s3-box-3-board ať to v případě budoucích změn nemusím udržovat duplicitní.
Vše co si přinesu domů je buď Shelly, nebo to skončí buď pod ESPhome nebo pod Zigbee2mqtt.
Ajťák co pamatuje BBS a OS/2 Warp a je mu jedno o jaký systém nebo síťařinu běží.
HA OS jako jedna z Proxmox VM na Odroid H3+/64GB https://github.com/tteck/Proxmox
Ajťák co pamatuje BBS a OS/2 Warp a je mu jedno o jaký systém nebo síťařinu běží.
HA OS jako jedna z Proxmox VM na Odroid H3+/64GB https://github.com/tteck/Proxmox
-
- Moderátor
- Příspěvky: 739
- Registrován: 03. červenec 2021, 18:35
- Dal poděkování: 84 poděkování
- Dostal poděkování: 175 poděkování
Re: ESP32-S3-BOX-3
Další pracovní verze:
- board směrován na repo Jesse
- vypisování/nevypisování URL = přepínač Výpisy předělány na terminálový výstup:
Je to pracovní verze, neodmazávám text - předpokládám že po nějakém čase se něco zaplní (max velikost text pole? paměť? ale té je spousta...) a dojde k restartu ESP.
- board směrován na repo Jesse
- vypisování/nevypisování URL = přepínač Výpisy předělány na terminálový výstup:
Je to pracovní verze, neodmazávám text - předpokládám že po nějakém čase se něco zaplní (max velikost text pole? paměť? ale té je spousta...) a dojde k restartu ESP.
Kód: Vybrat vše
esphome:
name: s3box3
friendly_name: S3box3
platformio_options:
board_build.flash_mode: dio
area: test room
# libraries: [regex]
esp32:
board: esp32s3box
flash_size: 16MB
framework:
type: esp-idf
sdkconfig_options:
CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240: "y"
CONFIG_ESP32S3_DATA_CACHE_64KB: "y"
CONFIG_ESP32S3_DATA_CACHE_LINE_64B: "y"
CONFIG_AUDIO_BOARD_CUSTOM: "y"
CONFIG_ESP32_S3_BOX_3_BOARD: "y"
components:
- name: esp32_s3_box_3_board
source: github://jesserockz/esp32-s3-box-3-board@main
refresh: 0s
# Enable logging
logger:
hardware_uart: USB_SERIAL_JTAG
level: DEBUG
logs:
component: ERROR
# Enable Home Assistant API
api:
encryption:
key: "jgVfSe0zIPTlfAEeM2zt5k2exvNL+6LK10sqsQ9qS3k="
ota:
password: "94431478a5e4b99a956cb61f1a9dcda8"
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "S3Box3 Fallback Hotspot"
password: "sDHiUghr0220"
captive_portal:
time:
- platform: homeassistant
id: hatime
timezone: Europe/Prague
# dashboard_import:
# package_import_url: github://esphome/firmware/voice-assistant/esp32-s3-box.yaml@main
binary_sensor:
- platform: gpio
pin:
number: GPIO1
inverted: true
name: "Mute"
- platform: gpio
pin:
number: GPIO0
mode: INPUT_PULLUP
inverted: true
name: Top Left Button
disabled_by_default: true
on_click:
- if:
condition:
switch.is_off: use_wake_word
then:
- if:
condition: voice_assistant.is_running
then:
- voice_assistant.stop:
- script.execute: reset_led
else:
- voice_assistant.start:
else:
- voice_assistant.stop
- delay: 1s
- script.execute: reset_led
- script.wait: reset_led
- voice_assistant.start_continuous:
- platform: status
id: api_connection
filters:
- delayed_on: 1s
on_press:
- if:
condition:
switch.is_on: use_wake_word
then:
- voice_assistant.start_continuous:
on_release:
- if:
condition:
switch.is_on: use_wake_word
then:
- voice_assistant.stop:
output:
- platform: ledc
pin: GPIO47
id: backlight_output
frequency: 19531Hz
light:
- platform: monochromatic
output: backlight_output
name: LCD Backlight
id: led
restore_mode: ALWAYS_OFF
disabled_by_default: true
default_transition_length: 0s
effects:
- pulse:
name: "Slow Pulse"
transition_length: 250ms
update_interval: 250ms
- pulse:
name: "Fast Pulse"
transition_length: 50ms
update_interval: 50ms
microphone:
- platform: esp_adf
id: box_mic
speaker:
- platform: esp_adf
id: box_speaker
voice_assistant:
id: va
microphone: box_mic
speaker: box_speaker
use_wake_word: true
noise_suppression_level: 2
auto_gain: 31dBFS
volume_multiplier: 2.0
vad_threshold: 3
on_listening:
- light.turn_on:
id: led
brightness: 100%
effect: "Slow Pulse"
on_tts_start:
- light.turn_on:
id: led
brightness: 75%
effect: "Slow Pulse"
- text_sensor.template.publish:
id: textline
state: !lambda |
return id(textline).state + "\n<black>" + id(hatime).now().strftime("%X") + " " + x;
on_end:
- delay: 100ms
- wait_until:
not:
speaker.is_playing:
- script.execute: reset_led
on_error:
- light.turn_on:
id: led
brightness: 50%
effect: "Fast Pulse"
- delay: 1s
- script.execute: reset_led
- script.wait: reset_led
- lambda: |-
if (code == "wake-provider-missing" || code == "wake-engine-missing") {
id(use_wake_word).turn_off();
}
if (message == "Could not request start.") {
id(restart_script).execute();
}
if (message == "Unexpected error during wake-word-detection") {
id(restart_script).execute();
}
- text_sensor.template.publish:
id: textline
state: !lambda |
return id(textline).state + "\n<red>" + id(hatime).now().strftime("%X") + " " + code;
- text_sensor.template.publish:
id: textline
state: !lambda |
return id(textline).state + "\n<red>" + id(hatime).now().strftime("%X") + " " + message;
on_stt_end:
- text_sensor.template.publish:
id: textline
state: !lambda |
return id(textline).state + "\n<green>" + id(hatime).now().strftime("%X") + " " + x;
on_tts_end:
- if:
condition:
switch.is_on: show_url
then:
- text_sensor.template.publish:
id: textline
state: !lambda |
return id(textline).state + "\n<black>" + x;
# # state: !lambda return (strftime("%X", id(hatime).now())+" "+ message);
# # state: !lambda return ("Karel "+ x);
# # state: !lambda return strftime("%X", id(hatime).now().timestamp());
# # state: !lambda return id(hatime).now().timestamp_local().strftime("%X");
# state: !lambda return id(hatime).now().to_local_time_string();
# # state: !lambda return x;
on_client_connected:
- if:
condition:
switch.is_on: use_wake_word
then:
- voice_assistant.start_continuous:
- script.execute: reset_led
on_client_disconnected:
- if:
condition:
switch.is_on: use_wake_word
then:
- voice_assistant.stop:
- light.turn_off: led
script:
- id: reset_led
then:
- if:
condition:
switch.is_on: use_wake_word
then:
- light.turn_on:
id: led
brightness: 25%
effect: none
else:
- light.turn_off: led
- id: restart_script
then:
- voice_assistant.stop
- delay: 1s
# - text_sensor.template.publish:
# id: line4
# state: " "
# - text_sensor.template.publish:
# id: line5
# state: " "
- voice_assistant.start_continuous
switch:
- platform: template
name: Use wake word
id: use_wake_word
optimistic: true
restore_mode: RESTORE_DEFAULT_ON
entity_category: config
on_turn_on:
- lambda: id(va).set_use_wake_word(true);
- if:
condition:
not:
- voice_assistant.is_running
then:
- voice_assistant.start_continuous
- script.execute: reset_led
on_turn_off:
- voice_assistant.stop
- lambda: id(va).set_use_wake_word(false);
- script.execute: reset_led
- platform: template
restore_mode: RESTORE_DEFAULT_ON
id: show_url
name: Show URL
optimistic: true
entity_category: config
external_components:
source: github://pr#5230
# source: github://kiklhorn/esphome
components: esp_adf
refresh: 0s
esp_adf:
board: esp32s3box3
# board: esp32s3box
psram:
mode: octal
speed: 120MHz
font:
- file: "gfonts://Roboto Condensed"
glyphs: "?!%()+,-/\\_.:;°<>0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZŽŠČŘĎŤŇĚÁÍÉÓÚŮÝ abcdefghijklmnopqrstuvwxyzμžščřďťňáěíóúůý₂³\n"
id: font1
size: 20
text_sensor:
- id: textline
platform: template
on_value:
then:
- component.update: my_display
- id: line0
platform: template
on_value:
then:
- component.update: my_display
# - platform: debug
# device:
# name: "Device Info"
# reset_reason:
# name: "Reset Reason"
# debug:
# update_interval: 5s
# sensor:
# - platform: debug
# # free:
# # name: "Heap Free"
# # fragmentation:
# # name: "Heap Fragmentation"
# # block:
# # name: "Heap Max Block"
# # loop_time:
# # name: "Loop Time"
# psram:
# name: "Free PSRAM"
spi:
clk_pin: GPIO7
mosi_pin: GPIO6
display:
- platform: ili9xxx
model: S3BOX
update_interval: 300s
id: my_display
# backlight_pin: GPIO4 #tento parametr mohu vynechat, a na GPIO4 pověsit PWM a řídit jas
cs_pin: GPIO5
dc_pin: GPIO4
# reset_pin: GPIO48 #Negation needed... ignore
reset_pin:
number: 48
inverted: true
# https://esphome.io/api/light__state_8cpp_source
lambda: |-
// 'batman', 32x13px
const unsigned char batman [] PROGMEM = {
0xff, 0xff, 0xff, 0xff, 0xff, 0x9f, 0xf9, 0xff, 0xfe, 0x3e, 0x7c, 0x7f, 0xf8, 0x3c, 0x3c, 0x1f,
0xf0, 0x1c, 0x38, 0x0f, 0xf0, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x07,
0xf0, 0x00, 0x00, 0x0f, 0xf0, 0xc4, 0x23, 0x0f, 0xf9, 0xfe, 0x7f, 0x9f, 0xfc, 0xfe, 0x7f, 0x3f,
0xff, 0xff, 0xff, 0xff
};
//it.image(0, 0, &batman);
for(auto i = 0; i<240; i++) {it.horizontal_line(0,i,320, my_blue.fade_to_white(i));}
it.rectangle(0, 0, it.get_width(), it.get_height(),color_red);
it.printf(60, 9, id(font1), "ESP32-S3-BOX-3");
int x = 2, yo = 43, offs = 34;
it.strftime(it.get_width()-2, 10, id(font1), color_green, TextAlign::TOP_RIGHT, "%H:%M", id(hatime).now());
auto ledcolor = Color(id(led).remote_values.get_red()*255, id(led).remote_values.get_green()*255, id(led).remote_values.get_blue()*255);
bool ledstatus = id(led).remote_values.get_state();
it.filled_circle(19, 19, 15, ledstatus ? ledcolor : color_black);
// it.printf(30, 0, id(font1), "%s", id(line0).state.c_str());
// it.printf(x, yo, id(font1), "%s", id(line1).state.c_str());
// it.printf(x, yo=yo+offs, id(font1), "%s", id(line2).state.c_str());
// it.printf(x, yo=yo+offs, id(font1), "%s", id(line3).state.c_str());
// it.printf(x, yo=yo+offs, id(font1), color_red, "%s", id(line4).state.c_str());
// it.printf(x, yo=yo+offs, id(font1), color_red, "%s", id(line5).state.c_str());
// # https://esphome.io/api/classesphome_1_1display_1_1_display.html
// ---------------------------- user defined parameters start here --------------------------
std::string text = id(textline).state.c_str();
auto used_font = id(font1);
int line_spacing = -5, line_height = used_font->get_height(); // -5 is usable spacing for dense lines
int first_line = 34; // "console" text output begins on "first_line". [pixels from top of the display]
int last_line = it.get_height() - line_height; //start of last text line (top left corner)
int left_offset = 3, right_offset = 0;
std::map<std::string, esphome::Color> colorCodes { // if left side found in the text then use previously user defined color (or define color directly here) from this map
{"<red>", color_red},
{"<green>", color_green},
{"<black>", color_black},
{"<blue>", esphome::Color(0, 0, 255)},
{"<white>", esphome::Color(255, 255, 255)},
// add more color codes here
};
esphome::Color currentColor = color_black; // default color
// ---------------------------- user defined parameters end --------------------------
std::vector<std::string> words;
std::vector<std::string> line;
std::vector<std::string> lines;
//std::slre r1(R"(([^\\ ])\n)");
//text = std::regex_replace(text, r1, "$1 \n"); // pokud není před \n mezera nebo \ doplň před \n mezeru
//std::regex r2(R"(\n([^ ]))");
//text = std::regex_replace(text, r2, "\n $1"); // pokud není před \n znak \ a zároveň za \n není mezera doplň za \n mezeru
for (size_t i = 0; i < text.size(); ++i) { // separate \n from letters around but keep \\n untouched
if (text[i] == '\n') {
if (i > 0 && text[i-1] != ' ' && (i < 2 || text[i-2] != '\\')) {
text.insert(i, " ");
++i;
}
if (i+1 < text.size() && text[i+1] != ' ' && text[i] != '\\') {
text.insert(i+1, " ");
++i;
}
}
}
auto cleanStringWidth = [&it, &colorCodes, &used_font](std::string input) -> int {
for (const auto& code : colorCodes) {
size_t foundPos = input.find(code.first);
if (foundPos != std::string::npos) {
input.erase(foundPos, code.first.length());
}
}
int x1, y1, width, height;
it.get_text_bounds(0, 0, (input+" ").c_str(), used_font, esphome::display::TextAlign::TOP_LEFT, &x1, &y1, &width, &height);
return width;
};
size_t pos = 0;
std::string token;
while ((pos = text.find(" ")) != std::string::npos) {
token = text.substr(0, pos);
words.push_back(token);
text.erase(0, pos + 1);
}
words.push_back(text); // Add the last word
int maxWidth = it.get_width() - left_offset - right_offset;
int lineWidth = 0;
std::string space = " ";
for (const auto& w : words) {
int x1, y1, width, height;
if (w == "\n") { // Check if the current word is a line break - it§s allready whole words only
std::string lineStr; // If it's a line break, start a new line
for (const auto& word : line) {
lineStr += word + " ";
}
lines.push_back(lineStr);
line.clear();
lineWidth = 0;
} else { //word isn§t a line break
// If the word is too long, split it
// ------------------------------------------------
width = cleanStringWidth(w);
if (width > maxWidth) { // If the word is longer than the max width
if (!line.empty()) { // handle the last line out of order
std::string lineStr;
for (const auto& word : line) {
lineStr += word + " ";
}
line.push_back(lineStr); // store the last line
}
std::string part; // Split the word into smaller parts
if (!line.empty()) {
part = line.back(); line.clear();
}
// ESP_LOGE("custom", "part: %s, width: %d, lineWidth: %d", part.c_str(), width, lineWidth); //ok, this is the last, not full, line before long word
for (int i = 0; i < w.size(); i++) {
std::string nextPart = part + w[i];
if (lineWidth) {
width = lineWidth;
lineWidth = 0;
// ESP_LOGE("s3box3", "width: %d, lineWidth: %d, maxWidth: %d -----------------------------------------------------", width, lineWidth, maxWidth);
} else {
width = cleanStringWidth(nextPart);
}
// ESP_LOGE("s3box3", "nextPart): %s, width: %d, lineWidth: %d, maxWidth: %d", part.c_str(), width, lineWidth, maxWidth);
if (width > maxWidth) { // If adding another character would make the part too long
if (!part.empty()) { // Add the current part to the line and start a new part
lines.push_back(part);
}
part = w[i];
} else {
part += w[i]; // Add the character to the part
}
}
if (!part.empty()) { // Add the last part to the line
line.push_back(part); // continue then on the same line as the last part. If not desired use lines.push_back(part)
// ESP_LOGE("s3box3", "part): %s, width: %d, lineWidth: %d, maxWidth: %d", part.c_str(), width, lineWidth, maxWidth);
lineWidth = width;
}
}
//------------------------------------------------- end of the long word handling
else if (lineWidth + width <= maxWidth) {
// ESP_LOGE("s3box3", "width: %d, lineWidth: %d, maxWidth: %d", width, lineWidth, maxWidth);
lineWidth += width;
// ESP_LOGE("s3box3", "w: %s, width: %d, lineWidth: %d, maxWidth: %d", w.c_str(), width, lineWidth, maxWidth);
line.push_back(w);
} else { // concatenate all words in the line
std::string lineStr;
for (const auto& word : line) {
lineStr += word + " ";
}
// ESP_LOGE("s3box3", "lineStr: %s, width: %d, lineWidth: %d, maxWidth: %d", lineStr.c_str(), width, lineWidth, maxWidth);
lines.push_back(lineStr); // store the line
line.clear(); // start a new line
line.push_back(w);
lineWidth = width;
}
}
}
if (!line.empty()) { // handle the last line
std::string lineStr;
for (const auto& word : line) {
lineStr += word + " ";
}
lines.push_back(lineStr); // store the last line
}
// now you know the number of lines before printing
int line_count = lines.size();
int start_line = 0;
int max_lines_count = int((last_line+line_spacing-first_line)/(line_height+line_spacing)); //last line without spacing after
if (line_count > max_lines_count) {
start_line = line_count - max_lines_count -1;
}
// print the lines
for (int i = start_line, j = 0; i < line_count; ++i, ++j) {
int y = first_line + j * (int)(line_height + line_spacing);
std::string& line = lines[i];
size_t lastPos = 0;
size_t nextPos = std::string::npos;
int new_begin_position = 0;
// Find the nearest color code
for (const auto& code : colorCodes) {
size_t pos = line.find(code.first, lastPos);
if (pos != std::string::npos && (nextPos == std::string::npos || pos < nextPos)) {
nextPos = pos;
}
}
while (nextPos != std::string::npos) {
// Print the part of the line before the color code
std::string textPiece = line.substr(lastPos, nextPos - lastPos);
it.print(left_offset+new_begin_position, y, used_font, currentColor, textPiece.c_str());
// Update position
int x1, y1, width, height;
it.get_text_bounds(0,0,textPiece.c_str(), used_font, esphome::display::TextAlign::TOP_LEFT, &x1, &y1, &width, &height);
new_begin_position += width;
// Update the color based on the color code
for (const auto& code : colorCodes) {
if (line.compare(nextPos, code.first.size(), code.first) == 0) {
currentColor = code.second;
lastPos = nextPos + code.first.size();
break;
}
}
nextPos = std::string::npos;
// Find the next nearest color code
for (const auto& code : colorCodes) {
size_t pos = line.find(code.first, lastPos);
if (pos != std::string::npos && (nextPos == std::string::npos || pos < nextPos)) {
nextPos = pos;
}
}
}
// Print the remainder of the line
std::string textPiece = line.substr(lastPos);
it.print(left_offset+new_begin_position, y, used_font, currentColor, textPiece.c_str());
}
color:
- id: color_red
red: 1
green: 0
blue: 0
- id: color_green
red: 0
green: 1
blue: 0
- id: color_black
red: 0
green: 0
blue: 0
- id: my_blue
blue: 100%
- id: my_red
red: 100%
- id: my_green
green: 70%
- id: my_white
red: 100%
blue: 100%
green: 100%
- id: my_yellow
hex: ffff00
Vše co si přinesu domů je buď Shelly, nebo to skončí buď pod ESPhome nebo pod Zigbee2mqtt.
Ajťák co pamatuje BBS a OS/2 Warp a je mu jedno o jaký systém nebo síťařinu běží.
HA OS jako jedna z Proxmox VM na Odroid H3+/64GB https://github.com/tteck/Proxmox
Ajťák co pamatuje BBS a OS/2 Warp a je mu jedno o jaký systém nebo síťařinu běží.
HA OS jako jedna z Proxmox VM na Odroid H3+/64GB https://github.com/tteck/Proxmox
-
- Moderátor
- Příspěvky: 739
- Registrován: 03. červenec 2021, 18:35
- Dal poděkování: 84 poděkování
- Dostal poděkování: 175 poděkování
Re: ESP32-S3-BOX-3
Rozchodil jsem i touchpanel, zatím kromě červeného kroužku.
Použit pro pager stránek.
Použit pro pager stránek.
Kód: Vybrat vše
esphome:
name: s3box3
friendly_name: S3box3
platformio_options:
board_build.flash_mode: dio
area: test room
# libraries: [regex]
esp32:
board: esp32s3box
flash_size: 16MB
framework:
type: esp-idf
sdkconfig_options:
CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240: "y"
CONFIG_ESP32S3_DATA_CACHE_64KB: "y"
CONFIG_ESP32S3_DATA_CACHE_LINE_64B: "y"
CONFIG_AUDIO_BOARD_CUSTOM: "y"
CONFIG_ESP32_S3_BOX_3_BOARD: "y"
components:
- name: esp32_s3_box_3_board
source: github://jesserockz/esp32-s3-box-3-board@main
refresh: 0s
# Enable logging
logger:
hardware_uart: USB_SERIAL_JTAG
# level: NONE
level: DEBUG
logs:
component: ERROR
# Enable Home Assistant API
api:
encryption:
key: "jgVfSe0zIPTlfAEeM2zt5k2exvNL+6LK10sqsQ9qS3k="
ota:
password: "94431478a5e4b99a956cb61f1a9dcda8"
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "S3Box3 Fallback Hotspot"
password: "sDHiUghr0220"
captive_portal:
time:
- platform: homeassistant
id: hatime
timezone: Europe/Prague
# dashboard_import:
# package_import_url: github://esphome/firmware/voice-assistant/esp32-s3-box.yaml@main
binary_sensor:
- platform: touchscreen
name: Top Half Touch Button
id: top_half_button
touchscreen_id: gt911_touchscreen
internal: true
x_min: 0
x_max: 340
y_min: 30
y_max: 120
on_click:
then:
- number.increment:
id: list_offset
cycle: False
- platform: touchscreen
name: Bottom Half Touch Button
id: bottom_half_button
touchscreen_id: gt911_touchscreen
internal: true
x_min: 0
x_max: 340
y_min: 121
y_max: 240
on_click:
then:
- number.decrement:
id: list_offset
cycle: False
- platform: gpio
pin:
number: GPIO1
inverted: true
name: "Mute"
- platform: gpio
pin:
number: GPIO0
mode: INPUT_PULLUP
inverted: true
name: Top Left Button
disabled_by_default: true
on_click:
- if:
condition:
switch.is_off: use_wake_word
then:
- if:
condition: voice_assistant.is_running
then:
- voice_assistant.stop:
- script.execute: reset_led
else:
- voice_assistant.start:
else:
- voice_assistant.stop
- delay: 1s
- script.execute: reset_led
- script.wait: reset_led
- voice_assistant.start_continuous:
- platform: status
id: api_connection
filters:
- delayed_on: 3s
on_press:
- if:
condition:
switch.is_on: use_wake_word
then:
- voice_assistant.start_continuous:
on_release:
- if:
condition:
switch.is_on: use_wake_word
then:
- voice_assistant.stop:
output:
- platform: ledc
pin: GPIO47
id: backlight_output
frequency: 19531Hz
light:
- platform: monochromatic
output: backlight_output
name: LCD Backlight
id: led
restore_mode: ALWAYS_OFF
disabled_by_default: true
default_transition_length: 0s
effects:
- pulse:
name: "Slow Pulse"
transition_length: 250ms
update_interval: 250ms
- pulse:
name: "Fast Pulse"
transition_length: 50ms
update_interval: 50ms
microphone:
- platform: esp_adf
id: box_mic
speaker:
- platform: esp_adf
id: box_speaker
voice_assistant:
id: va
microphone: box_mic
speaker: box_speaker
use_wake_word: true
noise_suppression_level: 2
auto_gain: 31dBFS
volume_multiplier: 2.0
vad_threshold: 3
on_listening:
- light.turn_on:
id: led
brightness: 100%
effect: "Slow Pulse"
on_tts_start:
- light.turn_on:
id: led
brightness: 75%
effect: "Slow Pulse"
- text_sensor.template.publish:
id: textline
state: !lambda |
return id(textline).state + "\n<black>" + id(hatime).now().strftime("%X") + " " + x;
on_end:
- delay: 100ms
- wait_until:
not:
speaker.is_playing:
- script.execute: reset_led
on_error:
- light.turn_on:
id: led
brightness: 50%
effect: "Fast Pulse"
- delay: 1s
- script.execute: reset_led
- script.wait: reset_led
- lambda: |-
if (code == "wake-provider-missing" || code == "wake-engine-missing") {
id(use_wake_word).turn_off();
}
if (message == "Could not request start.") {
id(restart_script).execute();
}
if (message == "Unexpected error during wake-word-detection") {
id(restart_script).execute();
}
- text_sensor.template.publish:
id: textline
state: !lambda |
return id(textline).state + "\n<red>" + id(hatime).now().strftime("%X") + " " + code;
- text_sensor.template.publish:
id: textline
state: !lambda |
return id(textline).state + "\n<red>" + id(hatime).now().strftime("%X") + " " + message;
on_stt_end:
- text_sensor.template.publish:
id: textline
state: !lambda |
return id(textline).state + "\n<green>" + id(hatime).now().strftime("%X") + " " + x;
on_tts_end:
- if:
condition:
switch.is_on: show_url
then:
- text_sensor.template.publish:
id: textline
state: !lambda |
return id(textline).state + "\n<black>" + x;
# # state: !lambda return (strftime("%X", id(hatime).now())+" "+ message);
# # state: !lambda return ("Karel "+ x);
# # state: !lambda return strftime("%X", id(hatime).now().timestamp());
# # state: !lambda return id(hatime).now().timestamp_local().strftime("%X");
# state: !lambda return id(hatime).now().to_local_time_string();
# # state: !lambda return x;
on_client_connected:
- if:
condition:
switch.is_on: use_wake_word
then:
- voice_assistant.start_continuous:
- script.execute: reset_led
on_client_disconnected:
- if:
condition:
switch.is_on: use_wake_word
then:
- voice_assistant.stop:
- light.turn_off: led
script:
- id: reset_led
then:
- if:
condition:
switch.is_on: use_wake_word
then:
- light.turn_on:
id: led
brightness: 25%
effect: none
else:
- light.turn_off: led
- id: restart_script
then:
- voice_assistant.stop
- delay: 1s
# - text_sensor.template.publish:
# id: line4
# state: " "
# - text_sensor.template.publish:
# id: line5
# state: " "
- voice_assistant.start_continuous
switch:
- platform: restart
name: "Restart $device_name"
- platform: safe_mode
name: "Restart (Safe Mode) $device_name"
- platform: template
name: Use wake word
id: use_wake_word
optimistic: true
restore_mode: RESTORE_DEFAULT_ON
entity_category: config
on_turn_on:
- lambda: id(va).set_use_wake_word(true);
- if:
condition:
not:
- voice_assistant.is_running
then:
- voice_assistant.start_continuous
- script.execute: reset_led
on_turn_off:
- voice_assistant.stop
- lambda: id(va).set_use_wake_word(false);
- script.execute: reset_led
- platform: template
restore_mode: RESTORE_DEFAULT_ON
id: show_url
name: Show URL
optimistic: true
entity_category: config
external_components:
- source: github://pr#5230
# - source: github://kiklhorn/esphome
components: esp_adf
refresh: 0s
- source: github://kiklhorn/components
components: gt911
refresh: 0s
# - source:
# type: local
# path: components
# components: gt911
i2c:
id: i2cbus
sda: GPIO8
scl: GPIO18
scan: True
frequency: 400kHz
# [18:13:55][I][i2c.idf:077]: Results from i2c bus scan:
# [18:13:55][I][i2c.idf:083]: Found i2c device at address 0x18 ES8311 Audio Controller
# [18:13:55][I][i2c.idf:083]: Found i2c device at address 0x40 ES7210 MIC ADC // ATECC608A-TNGTLSU-B ??? 7bit
# [18:13:55][I][i2c.idf:083]: Found i2c device at address 0x5D ??? Touchscreen CTP_2.0inch ??? GT911!!! ATECC608A-TNGTLSU-B
# [18:13:55][I][i2c.idf:083]: Found i2c device at address 0x68 ICM-42607-P 6 axis IMU
# define BSP_I2C_EXPAND_SCL (GPIO_NUM_40)
# define BSP_I2C_EXPAND_SDA (GPIO_NUM_41)
# define BSP_RADAR_OUT_IO (GPIO_NUM_21)
# define BSP_IR_CTRL_GPIO (GPIO_NUM_44)
# define BSP_IR_TX_GPIO (GPIO_NUM_39)
# define BSP_IR_RX_GPIO (GPIO_NUM_38)
touchscreen:
- platform: gt911
display: my_display
id: gt911_touchscreen
interrupt_pin: GPIO3
# on_touch:
# then:
# - text_sensor.template.publish:
# id: textline
# state: !lambda |
# return id(textline).state + "\n<white>" + id(hatime).now().strftime("%X") + " Touch " + " X: " + std::to_string(touch.x) + " Y: " + std::to_string(touch.y); //# x,y,id,state
# external_components:
# - source:
# type: local
# path: my_components
# components: [gt911]
# https://github.com/jesserockz/m5paper-esphome/tree/main/components/gt911
# https://components.espressif.com/components/espressif/esp_lcd_touch_gt911
# touchscreen:
# - platform: gt911
# #display:
# id: gt911_touchscreen
# interrupt_pin: GPIO36
# on_touch:
# - logger.log:
# format: Touch at (%d, %d)
# args: [touch.x, touch.y]
esp_adf:
board: esp32s3box3
# board: esp32s3box
psram:
mode: octal
speed: 120MHz
font:
- file: "gfonts://Roboto Condensed"
glyphs: "?!%()+,-/\\_.:;°<>0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZŽŠČŘĎŤŇĚÁÍÉÓÚŮÝ abcdefghijklmnopqrstuvwxyzμžščřďťňáěíóúůý₂³\n"
id: font1
size: 20
text_sensor:
- id: textline
platform: template
on_value:
then:
- component.update: my_display
number:
- platform: template
id: list_offset
optimistic: True
step: 1
min_value: 0
max_value: 1000
on_value:
then:
- component.update: my_display
initial_value: 0
restore_value: False
# - platform: debug
# device:
# name: "Device Info"
# reset_reason:
# name: "Reset Reason"
# debug:
# update_interval: 5s
# sensor:
# - platform: debug
# # free:
# # name: "Heap Free"
# # fragmentation:
# # name: "Heap Fragmentation"
# # block:
# # name: "Heap Max Block"
# # loop_time:
# # name: "Loop Time"
# psram:
# name: "Free PSRAM"
spi:
clk_pin: GPIO7
mosi_pin: GPIO6
display:
- platform: ili9xxx
model: S3BOX
rotation: 0
update_interval: 30s
id: my_display
# backlight_pin: GPIO4 #tento parametr mohu vynechat, a na GPIO4 pověsit PWM a řídit jas
cs_pin: GPIO5
dc_pin: GPIO4
# reset_pin: GPIO48 #Negation needed...
reset_pin:
number: 48
inverted: true
# https://esphome.io/api/light__state_8cpp_source
lambda: |-
// 'batman', 32x13px
const unsigned char batman [] PROGMEM = {
0xff, 0xff, 0xff, 0xff, 0xff, 0x9f, 0xf9, 0xff, 0xfe, 0x3e, 0x7c, 0x7f, 0xf8, 0x3c, 0x3c, 0x1f,
0xf0, 0x1c, 0x38, 0x0f, 0xf0, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x07,
0xf0, 0x00, 0x00, 0x0f, 0xf0, 0xc4, 0x23, 0x0f, 0xf9, 0xfe, 0x7f, 0x9f, 0xfc, 0xfe, 0x7f, 0x3f,
0xff, 0xff, 0xff, 0xff
};
//it.image(0, 0, &batman);
int gradient_max = 190; double gradient_step = double(gradient_max)/it.get_height();
for(auto i = 0; i<it.get_height(); i++) {it.horizontal_line(0,i,it.get_width(), my_blue.fade_to_white(i*gradient_step));}
it.rectangle(0, 0, it.get_width(), it.get_height(),color_red);
it.printf(60, 9, id(font1), "ESP32-S3-BOX-3");
int x = 2, yo = 43, offs = 34;
it.strftime(it.get_width()-2, 10, id(font1), color_green, TextAlign::TOP_RIGHT, "%H:%M", id(hatime).now());
auto ledcolor = Color(id(led).remote_values.get_red()*255, id(led).remote_values.get_green()*255, id(led).remote_values.get_blue()*255);
bool ledstatus = id(led).remote_values.get_state();
it.filled_circle(19, 19, 15, ledstatus ? ledcolor : color_black);
it.printf(217, 9, id(font1), int(id(list_offset).state) ? "P: -%d" : " ", int(id(list_offset).state));
// it.printf(x, yo, id(font1), "%s", id(line1).state.c_str());
// it.printf(x, yo=yo+offs, id(font1), "%s", id(line2).state.c_str());
// it.printf(x, yo=yo+offs, id(font1), "%s", id(line3).state.c_str());
// it.printf(x, yo=yo+offs, id(font1), color_red, "%s", id(line4).state.c_str());
// it.printf(x, yo=yo+offs, id(font1), color_red, "%s", id(line5).state.c_str());
// # https://esphome.io/api/classesphome_1_1display_1_1_display.html
// ---------------------------- user defined parameters start here --------------------------
std::string text = id(textline).state.c_str();
auto used_font = id(font1);
int line_spacing = -5, line_height = used_font->get_height(); // -5 is usable spacing for dense lines
int first_line = 34; // "console" text output begins on "first_line". [pixels from top of the display]
int last_line = it.get_height() - line_height; //start of last text line (top left corner)
int left_offset = 3, right_offset = 0;
std::map<std::string, esphome::Color> colorCodes { // if left side found in the text then use previously user defined color (or define color directly here) from this map
{"<red>", color_red},
{"<green>", color_green},
{"<black>", color_black},
{"<blue>", esphome::Color(0, 0, 255)},
{"<white>", esphome::Color(255, 255, 255)},
// add more color codes here
};
esphome::Color currentColor = color_black; // default color
// ---------------------------- user defined parameters end --------------------------
std::vector<std::string> words;
std::vector<std::string> line;
std::vector<std::string> lines;
//std::slre r1(R"(([^\\ ])\n)");
//text = std::regex_replace(text, r1, "$1 \n"); // pokud není před \n mezera nebo \ doplň před \n mezeru
//std::regex r2(R"(\n([^ ]))");
//text = std::regex_replace(text, r2, "\n $1"); // pokud není před \n znak \ a zároveň za \n není mezera doplň za \n mezeru
for (size_t i = 0; i < text.size(); ++i) { // separate \n from letters around but keep \\n untouched
if (text[i] == '\n') {
if (i > 0 && text[i-1] != ' ' && (i < 2 || text[i-2] != '\\')) {
text.insert(i, " ");
++i;
}
if (i+1 < text.size() && text[i+1] != ' ' && text[i] != '\\') {
text.insert(i+1, " ");
++i;
}
}
}
auto cleanStringWidth = [&it, &colorCodes, &used_font](std::string input) -> int {
for (const auto& code : colorCodes) {
size_t foundPos = input.find(code.first);
if (foundPos != std::string::npos) {
input.erase(foundPos, code.first.length());
}
}
int x1, y1, width, height;
it.get_text_bounds(0, 0, (input+" ").c_str(), used_font, esphome::display::TextAlign::TOP_LEFT, &x1, &y1, &width, &height);
return width;
};
size_t pos = 0;
std::string token;
while ((pos = text.find(" ")) != std::string::npos) {
token = text.substr(0, pos);
words.push_back(token);
text.erase(0, pos + 1);
}
words.push_back(text); // Add the last word
int maxWidth = it.get_width() - left_offset - right_offset;
int lineWidth = 0;
std::string space = " ";
for (const auto& w : words) {
int x1, y1, width, height;
if (w == "\n") { // Check if the current word is a line break - it§s allready whole words only
std::string lineStr; // If it's a line break, start a new line
for (const auto& word : line) {
lineStr += word + " ";
}
lines.push_back(lineStr);
line.clear();
lineWidth = 0;
} else { //word isn§t a line break
// If the word is too long, split it
// ------------------------------------------------
width = cleanStringWidth(w);
if (width > maxWidth) { // If the word is longer than the max width
if (!line.empty()) { // handle the last line out of order
std::string lineStr;
for (const auto& word : line) {
lineStr += word + " ";
}
line.push_back(lineStr); // store the last line
}
std::string part; // Split the word into smaller parts
if (!line.empty()) {
part = line.back(); line.clear();
}
// ESP_LOGE("custom", "part: %s, width: %d, lineWidth: %d", part.c_str(), width, lineWidth); //ok, this is the last, not full, line before long word
for (int i = 0; i < w.size(); i++) {
std::string nextPart = part + w[i];
if (lineWidth) {
width = lineWidth;
lineWidth = 0;
// ESP_LOGE("s3box3", "width: %d, lineWidth: %d, maxWidth: %d -----------------------------------------------------", width, lineWidth, maxWidth);
} else {
width = cleanStringWidth(nextPart);
}
// ESP_LOGE("s3box3", "nextPart): %s, width: %d, lineWidth: %d, maxWidth: %d", part.c_str(), width, lineWidth, maxWidth);
if (width > maxWidth) { // If adding another character would make the part too long
if (!part.empty()) { // Add the current part to the line and start a new part
lines.push_back(part);
}
part = w[i];
} else {
part += w[i]; // Add the character to the part
}
}
if (!part.empty()) { // Add the last part to the line
line.push_back(part); // continue then on the same line as the last part. If not desired use lines.push_back(part)
// ESP_LOGE("s3box3", "part): %s, width: %d, lineWidth: %d, maxWidth: %d", part.c_str(), width, lineWidth, maxWidth);
lineWidth = width;
}
}
//------------------------------------------------- end of the long word handling
else if (lineWidth + width <= maxWidth) {
// ESP_LOGE("s3box3", "width: %d, lineWidth: %d, maxWidth: %d", width, lineWidth, maxWidth);
lineWidth += width;
// ESP_LOGE("s3box3", "w: %s, width: %d, lineWidth: %d, maxWidth: %d", w.c_str(), width, lineWidth, maxWidth);
line.push_back(w);
} else { // concatenate all words in the line
std::string lineStr;
for (const auto& word : line) {
lineStr += word + " ";
}
// ESP_LOGE("s3box3", "lineStr: %s, width: %d, lineWidth: %d, maxWidth: %d", lineStr.c_str(), width, lineWidth, maxWidth);
lines.push_back(lineStr); // store the line
line.clear(); // start a new line
line.push_back(w);
lineWidth = width;
}
}
}
if (!line.empty()) { // handle the last line
std::string lineStr;
for (const auto& word : line) {
lineStr += word + " ";
}
lines.push_back(lineStr); // store the last line
}
// now you know the number of lines before printing
int line_count = lines.size();
int start_line = 0;
int max_lines_count = int((last_line+line_spacing-first_line)/(line_height+line_spacing)); //last line without spacing after
if (line_count > max_lines_count) {
start_line = line_count - max_lines_count -1;
start_line = start_line - id(list_offset).state * (max_lines_count - 1);
// start_line = std::max(0, start_line);
if (start_line < 0) {
start_line = 0;
id(list_offset).state = id(list_offset).state - 1;
// auto call = id(list_offset).make_call();
// call.number_decrement(false);
// call.perform();
}
}
// print the lines
for (int i = start_line, j = 0; i < line_count; ++i, ++j) {
int y = first_line + j * (int)(line_height + line_spacing);
std::string& line = lines[i];
size_t lastPos = 0;
size_t nextPos = std::string::npos;
int new_begin_position = 0;
// Find the nearest color code
for (const auto& code : colorCodes) {
size_t pos = line.find(code.first, lastPos);
if (pos != std::string::npos && (nextPos == std::string::npos || pos < nextPos)) {
nextPos = pos;
}
}
while (nextPos != std::string::npos) {
// Print the part of the line before the color code
std::string textPiece = line.substr(lastPos, nextPos - lastPos);
it.print(left_offset+new_begin_position, y, used_font, currentColor, textPiece.c_str());
// Update position
int x1, y1, width, height;
it.get_text_bounds(0,0,textPiece.c_str(), used_font, esphome::display::TextAlign::TOP_LEFT, &x1, &y1, &width, &height);
new_begin_position += width;
// Update the color based on the color code
for (const auto& code : colorCodes) {
if (line.compare(nextPos, code.first.size(), code.first) == 0) {
currentColor = code.second;
lastPos = nextPos + code.first.size();
break;
}
}
nextPos = std::string::npos;
// Find the next nearest color code
for (const auto& code : colorCodes) {
size_t pos = line.find(code.first, lastPos);
if (pos != std::string::npos && (nextPos == std::string::npos || pos < nextPos)) {
nextPos = pos;
}
}
}
// Print the remainder of the line
std::string textPiece = line.substr(lastPos);
it.print(left_offset+new_begin_position, y, used_font, currentColor, textPiece.c_str());
}
color:
- id: color_red
red: 1
green: 0
blue: 0
- id: color_green
red: 0
green: 1
blue: 0
- id: color_black
red: 0
green: 0
blue: 0
- id: my_blue
blue: 100%
- id: my_red
red: 100%
- id: my_green
green: 70%
- id: my_white
red: 100%
blue: 100%
green: 100%
- id: my_yellow
hex: ffff00
Vše co si přinesu domů je buď Shelly, nebo to skončí buď pod ESPhome nebo pod Zigbee2mqtt.
Ajťák co pamatuje BBS a OS/2 Warp a je mu jedno o jaký systém nebo síťařinu běží.
HA OS jako jedna z Proxmox VM na Odroid H3+/64GB https://github.com/tteck/Proxmox
Ajťák co pamatuje BBS a OS/2 Warp a je mu jedno o jaký systém nebo síťařinu běží.
HA OS jako jedna z Proxmox VM na Odroid H3+/64GB https://github.com/tteck/Proxmox
-
- Moderátor
- Příspěvky: 739
- Registrován: 03. červenec 2021, 18:35
- Dal poděkování: 84 poděkování
- Dostal poděkování: 175 poděkování
Re: ESP32-S3-BOX-3
Než se přesunu zpět k hodinkám tak bych rád dodělal pár drobností na displeji.
Aktuální chování je že pokud není zapnutý wake word tak zhasne displej.
Rád bych upravil stavový řádek - hodiny, virtuální LED (udělám zas barevnou jak M5Stack), wifi a baterie je mi jasná
Jakou ikonou indikovat čekání na wake word? A vůbec všechny on_něco automatizace https://esphome.io/components/voice_assistant.html
ikony zde: https://pictogrammers.com/library/mdi/
Aktuální chování je že pokud není zapnutý wake word tak zhasne displej.
Rád bych upravil stavový řádek - hodiny, virtuální LED (udělám zas barevnou jak M5Stack), wifi a baterie je mi jasná
Jakou ikonou indikovat čekání na wake word? A vůbec všechny on_něco automatizace https://esphome.io/components/voice_assistant.html
ikony zde: https://pictogrammers.com/library/mdi/
Vše co si přinesu domů je buď Shelly, nebo to skončí buď pod ESPhome nebo pod Zigbee2mqtt.
Ajťák co pamatuje BBS a OS/2 Warp a je mu jedno o jaký systém nebo síťařinu běží.
HA OS jako jedna z Proxmox VM na Odroid H3+/64GB https://github.com/tteck/Proxmox
Ajťák co pamatuje BBS a OS/2 Warp a je mu jedno o jaký systém nebo síťařinu běží.
HA OS jako jedna z Proxmox VM na Odroid H3+/64GB https://github.com/tteck/Proxmox
- Pete30
- Moderátor
- Příspěvky: 2901
- Registrován: 30. září 2020, 20:33
- Dal poděkování: 152 poděkování
- Dostal poděkování: 319 poděkování
Re: ESP32-S3-BOX-3
Ohledně ikon asi by se hodilo jestli tě dobře chápu, ale je to jen moje představa, třeba bude mít někdo lepší nápad
Jinak díky že se tomu věnuješ
já teď nemám vůbec čas a ještě se snažím dodělat co tu mám rozhrabané
Kód: Vybrat vše
icon: mdi:account-voice
icon: mdi:account-voice-off

Pokud nejsem přítomen tak jsem na rybách 

- Pete30
- Moderátor
- Příspěvky: 2901
- Registrován: 30. září 2020, 20:33
- Dal poděkování: 152 poděkování
- Dostal poděkování: 319 poděkování
-
- Moderátor
- Příspěvky: 739
- Registrován: 03. červenec 2021, 18:35
- Dal poděkování: 84 poděkování
- Dostal poděkování: 175 poděkování
Re: ESP32-S3-BOX-3
Popral jsem se s ikonami z google, takže stále není nutný žádný externí soubor
Ikony zleva doprava: Led jak u M5 verze, síla wifi, api připojení, jestli je zapnutý wake word, jestli voice assistant běží, jestli je režim continuous. případně kolik je nalistováno stran od konce výpisu, a hodiny.
Wake word a výpis URL se zapíná na straně HA, možná ještě dodělám přepínátko rovnou na dotykový displej.
Ikony odsud: https://fonts.google.com/icons?icon.pla ... al+Symbols
Glyphs = code point doplněný zleva o \U0000
Více v kódu.
Ikony zleva doprava: Led jak u M5 verze, síla wifi, api připojení, jestli je zapnutý wake word, jestli voice assistant běží, jestli je režim continuous. případně kolik je nalistováno stran od konce výpisu, a hodiny.
Wake word a výpis URL se zapíná na straně HA, možná ještě dodělám přepínátko rovnou na dotykový displej.
Ikony odsud: https://fonts.google.com/icons?icon.pla ... al+Symbols
Glyphs = code point doplněný zleva o \U0000
Více v kódu.
Kód: Vybrat vše
esphome:
name: s3box3
friendly_name: S3box3
platformio_options:
board_build.flash_mode: dio
area: test room
# libraries: [regex]
esp32:
board: esp32s3box
flash_size: 16MB
framework:
type: esp-idf
sdkconfig_options:
CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240: "y"
CONFIG_ESP32S3_DATA_CACHE_64KB: "y"
CONFIG_ESP32S3_DATA_CACHE_LINE_64B: "y"
CONFIG_AUDIO_BOARD_CUSTOM: "y"
CONFIG_ESP32_S3_BOX_3_BOARD: "y"
components:
- name: esp32_s3_box_3_board
source: github://jesserockz/esp32-s3-box-3-board@main
refresh: 0s
# Enable logging
logger:
hardware_uart: USB_SERIAL_JTAG
# level: NONE
level: DEBUG
logs:
component: ERROR
sensor: WARN
# Enable Home Assistant API
api:
encryption:
key: "jgVfSe0zIPTlfAEeM2zt5k2exvNL+6LK10sqsQ9qS3k="
id: haapi
ota:
password: "94431478a5e4b99a956cb61f1a9dcda8"
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "S3Box3 Fallback Hotspot"
password: "sDHiUghr0220"
captive_portal:
time:
- platform: homeassistant
id: hatime
timezone: Europe/Prague
# dashboard_import:
# package_import_url: github://esphome/firmware/voice-assistant/esp32-s3-box.yaml@main
substitutions:
rgbdin: GPIO41 #RGB LEDka
device_name: "s3box3"
binary_sensor:
- platform: touchscreen
name: Top Half Touch Button
id: top_half_button
touchscreen_id: gt911_touchscreen
internal: true
x_min: 0
x_max: 340
y_min: 30
y_max: 120
on_click:
then:
- number.increment:
id: list_offset
cycle: False
- platform: touchscreen
name: Bottom Half Touch Button
id: bottom_half_button
touchscreen_id: gt911_touchscreen
internal: true
x_min: 0
x_max: 340
y_min: 121
y_max: 240
on_click:
then:
- number.decrement:
id: list_offset
cycle: False
- platform: gpio
pin:
number: GPIO1
inverted: true
name: "Mute"
- platform: gpio
pin:
number: GPIO0
mode: INPUT_PULLUP
inverted: true
name: Top Left Button
disabled_by_default: true
on_click:
- if:
condition:
switch.is_off: use_wake_word
then:
- if:
condition: voice_assistant.is_running
then:
- voice_assistant.stop:
- script.execute: reset_led
else:
- voice_assistant.start:
else:
- voice_assistant.stop
- delay: 1s
- script.execute: reset_led
- script.wait: reset_led
- voice_assistant.start_continuous:
- component.update: my_display
- platform: status
id: api_connection
filters:
- delayed_on: 3s
on_press:
- if:
condition:
switch.is_on: use_wake_word
then:
- voice_assistant.start_continuous:
on_release:
- if:
condition:
switch.is_on: use_wake_word
then:
- voice_assistant.stop:
output:
- platform: ledc
pin: GPIO47
id: backlight_output
frequency: 19531Hz
light:
- platform: monochromatic
output: backlight_output
name: LCD Backlight
id: led
restore_mode: ALWAYS_OFF
disabled_by_default: true
default_transition_length: 0s
effects:
- pulse:
name: "Slow Pulse"
transition_length: 250ms
update_interval: 250ms
- pulse:
name: "Fast Pulse"
transition_length: 50ms
update_interval: 50ms
- platform: esp32_rmt_led_strip
id: rgbled
name: None
disabled_by_default: true
entity_category: config
pin: $rgbdin
default_transition_length: 0s
chipset: SK6812
num_leds: 1
rgb_order: grb
rmt_channel: 0
effects:
- pulse:
transition_length: 250ms
update_interval: 250ms
on_state:
then:
- component.update: my_display
microphone:
- platform: esp_adf
id: box_mic
speaker:
- platform: esp_adf
id: box_speaker
voice_assistant:
id: va
microphone: box_mic
speaker: box_speaker
use_wake_word: true
noise_suppression_level: 2
auto_gain: 31dBFS
volume_multiplier: 2.0
vad_threshold: 3
on_listening:
- light.turn_on:
id: led
brightness: 100%
effect: "Slow Pulse"
on_tts_start:
- light.turn_on:
id: led
brightness: 75%
effect: "Slow Pulse"
- light.turn_on:
id: rgbled
blue: 0%
red: 0%
green: 100%
brightness: 100%
effect: pulse
- text_sensor.template.publish:
id: textline
state: !lambda |
return id(textline).state + "\n<black>" + id(hatime).now().strftime("%X") + " " + x;
on_end:
- delay: 100ms
- wait_until:
not:
speaker.is_playing:
- script.execute: reset_led
on_error:
- light.turn_on:
id: led
brightness: 50%
effect: "Fast Pulse"
- light.turn_on:
id: rgbled
blue: 0%
red: 100%
green: 0%
brightness: 100%
effect: none
- delay: 1s
- script.execute: reset_led
- script.wait: reset_led
- lambda: |-
if (code == "wake-provider-missing" || code == "wake-engine-missing") {
id(use_wake_word).turn_off();
}
if (message == "Could not request start.") {
id(restart_script).execute();
}
if (message == "Unexpected error during wake-word-detection") {
id(restart_script).execute();
}
- text_sensor.template.publish:
id: textline
state: !lambda |
return id(textline).state + "\n<red>" + id(hatime).now().strftime("%X") + " " + code;
- text_sensor.template.publish:
id: textline
state: !lambda |
return id(textline).state + "\n<red>" + id(hatime).now().strftime("%X") + " " + message;
on_stt_end:
- text_sensor.template.publish:
id: textline
state: !lambda |
return id(textline).state + "\n<green>" + id(hatime).now().strftime("%X") + " " + x;
on_tts_end:
- if:
condition:
switch.is_on: show_url
then:
- text_sensor.template.publish:
id: textline
state: !lambda |
return id(textline).state + "\n<black>" + x;
# # state: !lambda return (strftime("%X", id(hatime).now())+" "+ message);
# # state: !lambda return ("Karel "+ x);
# # state: !lambda return strftime("%X", id(hatime).now().timestamp());
# # state: !lambda return id(hatime).now().timestamp_local().strftime("%X");
# state: !lambda return id(hatime).now().to_local_time_string();
# # state: !lambda return x;
on_client_connected:
- if:
condition:
switch.is_on: use_wake_word
then:
- voice_assistant.start_continuous:
- script.execute: reset_led
on_client_disconnected:
- if:
condition:
switch.is_on: use_wake_word
then:
- voice_assistant.stop:
- light.turn_off: led
script:
- id: reset_led
then:
- if:
condition:
switch.is_on: use_wake_word
then:
- light.turn_on:
id: led
brightness: 25%
effect: none
- light.turn_on:
id: rgbled
blue: 100%
red: 100%
green: 0%
brightness: 100%
effect: none
else:
- light.turn_off: rgbled
- light.turn_on:
id: led
brightness: 25%
effect: none
- id: restart_script
then:
- voice_assistant.stop
- delay: 1s
# - text_sensor.template.publish:
# id: line4
# state: " "
# - text_sensor.template.publish:
# id: line5
# state: " "
- voice_assistant.start_continuous
switch:
- platform: restart
name: "Restart $device_name"
- platform: safe_mode
name: "Restart (Safe Mode) $device_name"
- platform: template
name: "Use wake word"
id: use_wake_word
optimistic: true
restore_mode: RESTORE_DEFAULT_ON
entity_category: config
on_turn_on:
- lambda: id(va).set_use_wake_word(true);
- if:
condition:
not:
- voice_assistant.is_running
then:
- voice_assistant.start_continuous
- script.execute: reset_led
on_turn_off:
- voice_assistant.stop
- lambda: id(va).set_use_wake_word(false);
- script.execute: reset_led
- platform: template
restore_mode: RESTORE_DEFAULT_ON
id: show_url
name: Show URL
optimistic: true
entity_category: config
external_components:
- source: github://pr#5230
# - source: github://kiklhorn/esphome
components: esp_adf
refresh: 0s
- source: github://kiklhorn/components
components: gt911
refresh: 0s
# - source:
# type: local
# path: components
# components: gt911
i2c:
id: i2cbus
sda: GPIO8
scl: GPIO18
scan: True
frequency: 400kHz
# [18:13:55][I][i2c.idf:077]: Results from i2c bus scan:
# [18:13:55][I][i2c.idf:083]: Found i2c device at address 0x18 ES8311 Audio Controller
# [18:13:55][I][i2c.idf:083]: Found i2c device at address 0x40 ES7210 MIC ADC // ATECC608A-TNGTLSU-B ??? 7bit
# [18:13:55][I][i2c.idf:083]: Found i2c device at address 0x5D ??? Touchscreen CTP_2.0inch ??? GT911!!! ATECC608A-TNGTLSU-B
# [18:13:55][I][i2c.idf:083]: Found i2c device at address 0x68 ICM-42607-P 6 axis IMU
# define BSP_I2C_EXPAND_SCL (GPIO_NUM_40)
# define BSP_I2C_EXPAND_SDA (GPIO_NUM_41)
# define BSP_RADAR_OUT_IO (GPIO_NUM_21)
# define BSP_IR_CTRL_GPIO (GPIO_NUM_44)
# define BSP_IR_TX_GPIO (GPIO_NUM_39)
# define BSP_IR_RX_GPIO (GPIO_NUM_38)
touchscreen:
- platform: gt911
display: my_display
id: gt911_touchscreen
interrupt_pin: GPIO3
# on_touch:
# then:
# - text_sensor.template.publish:
# id: textline
# state: !lambda |
# return id(textline).state + "\n<white>" + id(hatime).now().strftime("%X") + " Touch " + " X: " + std::to_string(touch.x) + " Y: " + std::to_string(touch.y); //# x,y,id,state
# external_components:
# - source:
# type: local
# path: my_components
# components: [gt911]
# https://github.com/jesserockz/m5paper-esphome/tree/main/components/gt911
# https://components.espressif.com/components/espressif/esp_lcd_touch_gt911
# touchscreen:
# - platform: gt911
# #display:
# id: gt911_touchscreen
# interrupt_pin: GPIO36
# on_touch:
# - logger.log:
# format: Touch at (%d, %d)
# args: [touch.x, touch.y]
esp_adf:
board: esp32s3box3
# board: esp32s3box
psram:
mode: octal
speed: 120MHz
font:
- id: font1
size: 20
file: "gfonts://Roboto Condensed"
glyphs: "?!%()+,-/\\_.:;°<>0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZŽŠČŘĎŤŇĚÁÍÉÓÚŮÝ abcdefghijklmnopqrstuvwxyzμžščřďťňáéěíóúůý₂³\n"
- id: ikony
size: 35
# file: "gfonts://Material Icons"
file: 'gfonts://Material+Symbols+Outlined'
# mdi-icons google - https://fonts.google.com/icons?selected=Material+Symbols+Outlined:network_wifi_1_bar:FILL@0;wght@400;GRAD@0;opsz@24&icon.query=network+wifi+&icon.platform=web
glyphs: [
"\U0000e157", # link
"\U0000e16f", # link off
"\U0000e91f", # record voice over
"\U0000e94a", # voice over off
"\U0000f0b0", # signal wifi 0 bar
"\U0000ebe4", # network wifi 1 bar
"\U0000ebd6", # network wifi 2 bar
"\U0000ebe1", # network wifi 3 bar
"\U0000e1ba", # network wifi
"\U0000e1d8", # signal wifi 4 bar
"\U0000eb94", # ABC
"\U0000ebea", # spatial tracking
"\U0000eb3d", # all inclusive
"\U0000e566", # directions run
"\U0000e9b1", # hail
"\U0000f8e2", # man 3
"\U0000e84e", # accessibility
]
# mdi-icons, no google font
# glyphs: [
# '\U0000e425', # mdi-timer"
# '\U0000F05CB', # mdi-account-voice
# , # F0ED4, mdi-account-voice-off
# , # api
# , # api-off
# # Wifi
# '', # F092F mdi-wifi-strength-outline
# '', # F091F mdi-wifi-strength-1
# '', # F0922 mdi-wifi-strength-2
# '', # F0925 mdi-wifi-strength-3
# '', # F0928 mdi-wifi-strength-4
# ]
text_sensor:
- id: textline
platform: template
on_value:
then:
- component.update: my_display
number:
- platform: template
id: list_offset
optimistic: True
step: 1
min_value: 0
max_value: 1000
on_value:
then:
- component.update: my_display
initial_value: 0
restore_value: False
# - platform: debug
# device:
# name: "Device Info"
# reset_reason:
# name: "Reset Reason"
# debug:
# update_interval: 5s
sensor:
- platform: wifi_signal
id: wifisignal
name: "WiFi Signal Sensor"
update_interval: 5s # default 60s, neni nejlepší nápad nechat internal:false a nízký update interval - zbytečný provoz mqtt
internal: true
on_value:
then:
- component.update: my_display
spi:
clk_pin: GPIO7
mosi_pin: GPIO6
display:
- platform: ili9xxx
model: S3BOX
rotation: 0
update_interval: 30s
id: my_display
# backlight_pin: GPIO4 #tento parametr mohu vynechat, a na GPIO4 pověsit PWM a řídit jas
cs_pin: GPIO5
dc_pin: GPIO4
# reset_pin: GPIO48 #Negation needed...
reset_pin:
number: 48
inverted: true
# https://esphome.io/api/light__state_8cpp_source
lambda: |-
// 'batman', 32x13px
const unsigned char batman [] PROGMEM = {
0xff, 0xff, 0xff, 0xff, 0xff, 0x9f, 0xf9, 0xff, 0xfe, 0x3e, 0x7c, 0x7f, 0xf8, 0x3c, 0x3c, 0x1f,
0xf0, 0x1c, 0x38, 0x0f, 0xf0, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x07,
0xf0, 0x00, 0x00, 0x0f, 0xf0, 0xc4, 0x23, 0x0f, 0xf9, 0xfe, 0x7f, 0x9f, 0xfc, 0xfe, 0x7f, 0x3f,
0xff, 0xff, 0xff, 0xff
};
//it.image(0, 0, &batman);
int x,y, yo, offs;
int gradient_max = 190; double gradient_step = double(gradient_max)/it.get_height();
for(auto i = 0; i<it.get_height(); i++) {it.horizontal_line(0,i,it.get_width(), my_blue.fade_to_white(i*gradient_step));}
it.rectangle(0, 0, it.get_width(), it.get_height(),color_red);
// it.printf(80, 9, id(font1), "ESP32-S3-BOX-3");
//it.printf(45,9, id(ikony), id(use_wake_word).state ? "" : "" );
//it.printf(60,9, id(ikony), id(haapi).is_connected() ? "" : "");
// it.printf(45,9, id(ikony), color_red, id(use_wake_word).state ? "\U0000e91f" : "\U0000e94a" );
// it.printf(60,9, id(ikony), color_red, "%s", id(haapi).is_connected() ? "\U0000e157" : "\U0000e16f" );
// it.printf(60,9, id(ikony), color_red, id(haapi).is_connected() ? "\U0000e157" : "\U0000e16f" );
// WiFi Signal Strenght
x = 40, y = 0;
if(id(wifisignal).has_state()) {
// it.printf(0,10, id(ikony), " %.0f db", id(wifisignal).state);
if (id(wifisignal).state >= -45) {
//Excellent
it.print(x, y, id(ikony), TextAlign::TOP_LEFT, "\U0000e1d8");
} else if (id(wifisignal).state >= -50) {
//Excellent
it.print(x, y, id(ikony), TextAlign::TOP_LEFT, "\U0000e1ba");
// ESP_LOGI("WiFi", "Exellent");
} else if (id(wifisignal).state >= -60) {
//Good
it.print(x, y, id(ikony), TextAlign::TOP_LEFT, "\U0000ebe1");
// ESP_LOGI("WiFi", "Good");
} else if (id(wifisignal).state >= -67) {
//Fair
it.print(x, y, id(ikony), TextAlign::TOP_LEFT, "\U0000ebd6");
// ESP_LOGI("WiFi", "Fair");
} else if (id(wifisignal).state >= -70) {
//Weak
it.print(x, y, id(ikony), TextAlign::TOP_LEFT, "\U0000ebe4");
// ESP_LOGI("WiFi", "Weak");
} else {
//Unlikely working signal
it.print(x, y, id(ikony), TextAlign::TOP_LEFT, "\U0000f0b0");
// ESP_LOGI("WiFi", "Unlikely");
}
}
x=75, y=0;
if (id(haapi).is_connected()) {
it.print(x,y, id(ikony), color_white, "\U0000e157" );
} else {
it.print(x,y, id(ikony), color_red, "\U0000e16f" );
}
x=110, y=0;
if (id(use_wake_word).state) {
it.print(x,y, id(ikony), color_white, "\U0000e91f" );
} else {
it.print(x,y, id(ikony), color_red, "\U0000e94a" );
}
x=145, y=0;
if (id(va).is_running()) {
it.print(x,y, id(ikony), color_white, "\U0000e566" );
} else {
it.print(x,y, id(ikony), color_red, "\U0000e84e" );
}
x=170, y=0;
if (id(va).is_continuous()) {
it.print(x,y, id(ikony), color_white, "\U0000eb3d" );
} else {
it.print(x,y, id(ikony), color_red, "\U0000eb3d" );
}
/*
"\U0000eb3d", # all inclusive
"\U0000e566", # directions run
"\U0000e9b1", # hail
"\U0000f8e2", # man 3
"\U0000e84e", # accessibility
*/
it.strftime(it.get_width()-2, 10, id(font1), color_green, TextAlign::TOP_RIGHT, "%H:%M", id(hatime).now());
auto ledcolor = Color(id(rgbled).remote_values.get_red()*255, id(rgbled).remote_values.get_green()*255, id(rgbled).remote_values.get_blue()*255);
bool ledstatus = id(rgbled).remote_values.get_state();
it.filled_circle(19, 19, 15, ledstatus ? ledcolor : color_black);
it.printf(217, 9, id(font1), int(id(list_offset).state) ? "P: -%d" : " ", int(id(list_offset).state));
x = 2, yo = 43, offs = 34;
// it.printf(x, yo, id(font1), "%s", id(line1).state.c_str());
// it.printf(x, yo=yo+offs, id(font1), "%s", id(line2).state.c_str());
// it.printf(x, yo=yo+offs, id(font1), "%s", id(line3).state.c_str());
// it.printf(x, yo=yo+offs, id(font1), color_red, "%s", id(line4).state.c_str());
// it.printf(x, yo=yo+offs, id(font1), color_red, "%s", id(line5).state.c_str());
// # https://esphome.io/api/classesphome_1_1display_1_1_display.html
// ---------------------------- user defined parameters start here --------------------------
std::string text = id(textline).state.c_str();
auto used_font = id(font1);
int line_spacing = -5, line_height = used_font->get_height(); // -5 is usable spacing for dense lines
int first_line = 34; // "console" text output begins on "first_line". [pixels from top of the display]
int last_line = it.get_height() - line_height; //start of last text line (top left corner)
int left_offset = 3, right_offset = 0;
std::map<std::string, esphome::Color> colorCodes { // if left side found in the text then use previously user defined color (or define color directly here) from this map
{"<red>", color_red},
{"<green>", color_green},
{"<black>", color_black},
{"<blue>", esphome::Color(0, 0, 255)},
{"<white>", esphome::Color(255, 255, 255)},
// add more color codes here
};
esphome::Color currentColor = color_black; // default color
// ---------------------------- user defined parameters end --------------------------
std::vector<std::string> words;
std::vector<std::string> line;
std::vector<std::string> lines;
//std::slre r1(R"(([^\\ ])\n)");
//text = std::regex_replace(text, r1, "$1 \n"); // pokud není před \n mezera nebo \ doplň před \n mezeru
//std::regex r2(R"(\n([^ ]))");
//text = std::regex_replace(text, r2, "\n $1"); // pokud není před \n znak \ a zároveň za \n není mezera doplň za \n mezeru
for (size_t i = 0; i < text.size(); ++i) { // separate \n from letters around but keep \\n untouched
if (text[i] == '\n') {
if (i > 0 && text[i-1] != ' ' && (i < 2 || text[i-2] != '\\')) {
text.insert(i, " ");
++i;
}
if (i+1 < text.size() && text[i+1] != ' ' && text[i] != '\\') {
text.insert(i+1, " ");
++i;
}
}
}
auto cleanStringWidth = [&it, &colorCodes, &used_font](std::string input) -> int {
for (const auto& code : colorCodes) {
size_t foundPos = input.find(code.first);
if (foundPos != std::string::npos) {
input.erase(foundPos, code.first.length());
}
}
int x1, y1, width, height;
it.get_text_bounds(0, 0, (input+" ").c_str(), used_font, esphome::display::TextAlign::TOP_LEFT, &x1, &y1, &width, &height);
return width;
};
size_t pos = 0;
std::string token;
while ((pos = text.find(" ")) != std::string::npos) {
token = text.substr(0, pos);
words.push_back(token);
text.erase(0, pos + 1);
}
words.push_back(text); // Add the last word
int maxWidth = it.get_width() - left_offset - right_offset;
int lineWidth = 0;
std::string space = " ";
for (const auto& w : words) {
int x1, y1, width, height;
if (w == "\n") { // Check if the current word is a line break - it§s allready whole words only
std::string lineStr; // If it's a line break, start a new line
for (const auto& word : line) {
lineStr += word + " ";
}
lines.push_back(lineStr);
line.clear();
lineWidth = 0;
} else { //word isn§t a line break
// If the word is too long, split it
// ------------------------------------------------
width = cleanStringWidth(w);
if (width > maxWidth) { // If the word is longer than the max width
if (!line.empty()) { // handle the last line out of order
std::string lineStr;
for (const auto& word : line) {
lineStr += word + " ";
}
line.push_back(lineStr); // store the last line
}
std::string part; // Split the word into smaller parts
if (!line.empty()) {
part = line.back(); line.clear();
}
// ESP_LOGE("custom", "part: %s, width: %d, lineWidth: %d", part.c_str(), width, lineWidth); //ok, this is the last, not full, line before long word
for (int i = 0; i < w.size(); i++) {
std::string nextPart = part + w[i];
if (lineWidth) {
width = lineWidth;
lineWidth = 0;
// ESP_LOGE("s3box3", "width: %d, lineWidth: %d, maxWidth: %d -----------------------------------------------------", width, lineWidth, maxWidth);
} else {
width = cleanStringWidth(nextPart);
}
// ESP_LOGE("s3box3", "nextPart): %s, width: %d, lineWidth: %d, maxWidth: %d", part.c_str(), width, lineWidth, maxWidth);
if (width > maxWidth) { // If adding another character would make the part too long
if (!part.empty()) { // Add the current part to the line and start a new part
lines.push_back(part);
}
part = w[i];
} else {
part += w[i]; // Add the character to the part
}
}
if (!part.empty()) { // Add the last part to the line
line.push_back(part); // continue then on the same line as the last part. If not desired use lines.push_back(part)
// ESP_LOGE("s3box3", "part): %s, width: %d, lineWidth: %d, maxWidth: %d", part.c_str(), width, lineWidth, maxWidth);
lineWidth = width;
}
}
//------------------------------------------------- end of the long word handling
else if (lineWidth + width <= maxWidth) {
// ESP_LOGE("s3box3", "width: %d, lineWidth: %d, maxWidth: %d", width, lineWidth, maxWidth);
lineWidth += width;
// ESP_LOGE("s3box3", "w: %s, width: %d, lineWidth: %d, maxWidth: %d", w.c_str(), width, lineWidth, maxWidth);
line.push_back(w);
} else { // concatenate all words in the line
std::string lineStr;
for (const auto& word : line) {
lineStr += word + " ";
}
// ESP_LOGE("s3box3", "lineStr: %s, width: %d, lineWidth: %d, maxWidth: %d", lineStr.c_str(), width, lineWidth, maxWidth);
lines.push_back(lineStr); // store the line
line.clear(); // start a new line
line.push_back(w);
lineWidth = width;
}
}
}
if (!line.empty()) { // handle the last line
std::string lineStr;
for (const auto& word : line) {
lineStr += word + " ";
}
lines.push_back(lineStr); // store the last line
}
// now you know the number of lines before printing
int line_count = lines.size();
int start_line = 0;
int max_lines_count = int((last_line+line_spacing-first_line)/(line_height+line_spacing)); //last line without spacing after
if (line_count > max_lines_count) {
start_line = line_count - max_lines_count -1;
start_line = start_line - id(list_offset).state * (max_lines_count - 1);
// start_line = std::max(0, start_line);
if (start_line < 0) {
start_line = 0;
id(list_offset).state = id(list_offset).state - 1;
// auto call = id(list_offset).make_call();
// call.number_decrement(false);
// call.perform();
}
}
// print the lines
for (int i = start_line, j = 0; i < line_count; ++i, ++j) {
int y = first_line + j * (int)(line_height + line_spacing);
std::string& line = lines[i];
size_t lastPos = 0;
size_t nextPos = std::string::npos;
int new_begin_position = 0;
// Find the nearest color code
for (const auto& code : colorCodes) {
size_t pos = line.find(code.first, lastPos);
if (pos != std::string::npos && (nextPos == std::string::npos || pos < nextPos)) {
nextPos = pos;
}
}
while (nextPos != std::string::npos) {
// Print the part of the line before the color code
std::string textPiece = line.substr(lastPos, nextPos - lastPos);
it.print(left_offset+new_begin_position, y, used_font, currentColor, textPiece.c_str());
// Update position
int x1, y1, width, height;
it.get_text_bounds(0,0,textPiece.c_str(), used_font, esphome::display::TextAlign::TOP_LEFT, &x1, &y1, &width, &height);
new_begin_position += width;
// Update the color based on the color code
for (const auto& code : colorCodes) {
if (line.compare(nextPos, code.first.size(), code.first) == 0) {
currentColor = code.second;
lastPos = nextPos + code.first.size();
break;
}
}
nextPos = std::string::npos;
// Find the next nearest color code
for (const auto& code : colorCodes) {
size_t pos = line.find(code.first, lastPos);
if (pos != std::string::npos && (nextPos == std::string::npos || pos < nextPos)) {
nextPos = pos;
}
}
}
// Print the remainder of the line
std::string textPiece = line.substr(lastPos);
it.print(left_offset+new_begin_position, y, used_font, currentColor, textPiece.c_str());
}
color:
- id: color_red
red: 1
green: 0
blue: 0
- id: color_green
red_int: 0
green_int: 255
blue_int: 0
- id: color_black
red: 0
green: 0
blue: 0
- id: my_blue
blue: 100%
- id: my_red
red: 100%
- id: my_green
green: 70%
- id: color_white
red: 100%
blue: 100%
green: 100%
- id: my_yellow
hex: ffff00
Vše co si přinesu domů je buď Shelly, nebo to skončí buď pod ESPhome nebo pod Zigbee2mqtt.
Ajťák co pamatuje BBS a OS/2 Warp a je mu jedno o jaký systém nebo síťařinu běží.
HA OS jako jedna z Proxmox VM na Odroid H3+/64GB https://github.com/tteck/Proxmox
Ajťák co pamatuje BBS a OS/2 Warp a je mu jedno o jaký systém nebo síťařinu běží.
HA OS jako jedna z Proxmox VM na Odroid H3+/64GB https://github.com/tteck/Proxmox