279 lines
11 KiB
YAML
279 lines
11 KiB
YAML
###########################################
|
|
## ##
|
|
## filename: base.yaml ##
|
|
## description: contains configuration ##
|
|
## that will be the same for all the ##
|
|
## possible configurations ##
|
|
## ##
|
|
###########################################
|
|
|
|
esp32:
|
|
flash_size: 16MB
|
|
|
|
interval:
|
|
- interval: 1min
|
|
then:
|
|
- logger.log: "ESPHome for Button+ v0.1.1"
|
|
|
|
i2c:
|
|
- id: temperature_sensor
|
|
sda: GPIO1
|
|
scl: GPIO2
|
|
- id: buttons
|
|
sda: GPIO47
|
|
scl: GPIO48
|
|
frequency: 400khz
|
|
|
|
spi:
|
|
clk_pin: GPIO36
|
|
mosi_pin: GPIO35
|
|
|
|
globals:
|
|
- id: nr_of_pages
|
|
type: int
|
|
initial_value: '1'
|
|
- id: actual_page
|
|
type: int
|
|
initial_value: '0'
|
|
|
|
output:
|
|
- platform: ledc
|
|
pin: GPIO3
|
|
id: display_main_backlight_pwm
|
|
inverted: True
|
|
max_power: 1.0
|
|
frequency: 500Hz
|
|
- platform: ledc
|
|
pin: GPIO46
|
|
id: displays_mini_backlight_pwm
|
|
inverted: True
|
|
max_power: 0.6
|
|
frequency: 500Hz
|
|
|
|
sensor:
|
|
- platform: sts3x
|
|
id: inside_temperature
|
|
i2c_id: temperature_sensor
|
|
name: "Temperature"
|
|
address: 0x4A
|
|
update_interval: 10s
|
|
- platform: template
|
|
name: "Active Page ID"
|
|
id: active_page_id_ha
|
|
update_interval: never
|
|
|
|
text_sensor:
|
|
- platform: template
|
|
name: "Active Page Name"
|
|
id: active_page_name_ha
|
|
update_interval: never
|
|
|
|
light:
|
|
- platform: neopixelbus
|
|
id: neopixels
|
|
type: RGB
|
|
variant: WS2812
|
|
pin: GPIO4
|
|
num_leds: 17
|
|
- platform: monochromatic
|
|
output: display_main_backlight_pwm
|
|
gamma_correct : 2.2
|
|
name: "Main Display Backlight"
|
|
id: display_main_backlight
|
|
restore_mode: ALWAYS_ON
|
|
- platform: monochromatic
|
|
output: displays_mini_backlight_pwm
|
|
gamma_correct : 2.2
|
|
name: "Mini Display Backlight"
|
|
id: displays_mini_backlight
|
|
restore_mode: ALWAYS_ON
|
|
|
|
time:
|
|
- platform: homeassistant
|
|
id: datetime
|
|
|
|
number:
|
|
## Creates a number entity in Home Assistant
|
|
# It sets the menu of the Button Plus
|
|
- platform: template
|
|
name: "Menu Selector"
|
|
id: menuselector
|
|
optimistic: true
|
|
min_value: 0 # keep at 0
|
|
max_value: 10 # TODO replace page numbers with substitution
|
|
step: 1
|
|
on_value:
|
|
then:
|
|
- lambda: |-
|
|
if(id(menuselector).state >= id(nr_of_pages)) {
|
|
id(actual_page) = id(nr_of_pages)-1;
|
|
} else {
|
|
id(actual_page) = id(menuselector).state;
|
|
}
|
|
# # Refresh the screen
|
|
# - script.execute: update_page <<< this ends in an loop...
|
|
|
|
script:
|
|
######################
|
|
### paging scripts ###
|
|
######################
|
|
- id: next_page
|
|
then:
|
|
- lambda: |-
|
|
id(actual_page) = id(actual_page) + 1;
|
|
if(id(actual_page) >= id(nr_of_pages)) {
|
|
id(actual_page) = 0;
|
|
}
|
|
- script.execute: update_page
|
|
- id: prev_page
|
|
then:
|
|
- lambda: |-
|
|
id(actual_page) = id(actual_page) - 1;
|
|
if(id(actual_page) < 0) {
|
|
id(actual_page) = id(nr_of_pages) - 1;
|
|
}
|
|
- script.execute: update_page
|
|
- id: update_page
|
|
then:
|
|
- lambda: |-
|
|
id(active_page_name) = id(page_names)[id(actual_page)];
|
|
- sensor.template.publish:
|
|
id: active_page_id_ha
|
|
state: !lambda 'return id(actual_page);'
|
|
- text_sensor.template.publish:
|
|
id: active_page_name_ha
|
|
state: !lambda 'return id(active_page_name);'
|
|
- number.set:
|
|
id: menuselector
|
|
value: !lambda 'return id(actual_page);'
|
|
- script.execute: update_all
|
|
## display item constructor
|
|
# requires all of the following parameters as input
|
|
# it requires fonts and colors to be defined
|
|
# can be called as lambda, for instance
|
|
# id(displayitem).execute(160,2,"External","size_3_label","orange",id(outside_temperature).state,1,"","size_3_value","white","°C","size_3_unit","grey","TOP_LEFT");
|
|
# this will position a block with label "External" in size 3 and color orange
|
|
# below that a value with 1 decimal, in white, size 3
|
|
# next to that unit "°C", size 3 in grey
|
|
# anchored at x,y = 160,2 top left corner
|
|
- id: displayitem
|
|
parameters:
|
|
x: int # x of anchor point
|
|
y: int # y of anchor point
|
|
label: string # label, to be shown above the value
|
|
labelfont: string # any of size_1_value, size_2_unit, size_3_label and everything in between
|
|
labelcolor: string # any of white, orange, red, green or grey
|
|
valuenum: float # value to display (numerical)
|
|
decimals: int # rounding of value to display
|
|
valuestr: string # if left empty it will select display the value float
|
|
valuefont: string # any of size_1_value, size_2_unit, size_3_label and everything in between
|
|
valuecolor: string # any of white, orange, red, green or grey
|
|
unit: string # displayed unit
|
|
unitfont: string # any of size_1_value, size_2_unit, size_3_label and everything in between
|
|
unitcolor: string # any of white, orange, red, green or grey
|
|
align: string # TOP_LEFT, TOP_CENTER or TOP_RIGHT
|
|
then:
|
|
lambda: |-
|
|
// Helper to get the font object from its ID string
|
|
// This lambda function maps font ID strings to their corresponding font objects.
|
|
// If the provided font_id matches a known font, it returns the appropriate font object.
|
|
// Otherwise, it returns nullptr.
|
|
auto get_font = [](const std::string &font_id) -> esphome::font::Font* {
|
|
if (font_id == "size_1_value") return id(size_1_value);
|
|
if (font_id == "size_1_label") return id(size_1_label);
|
|
if (font_id == "size_1_unit") return id(size_1_unit);
|
|
if (font_id == "size_2_value") return id(size_2_value);
|
|
if (font_id == "size_2_label") return id(size_2_label);
|
|
if (font_id == "size_2_unit") return id(size_2_unit);
|
|
if (font_id == "size_3_value") return id(size_3_value);
|
|
if (font_id == "size_3_label") return id(size_3_label);
|
|
if (font_id == "size_3_unit") return id(size_3_unit);
|
|
return nullptr; // Return nullptr if the font ID doesn't match any known font.
|
|
};
|
|
|
|
auto get_color = [](const std::string &color_id) -> esphome::Color {
|
|
if (color_id == "white") return id(white);
|
|
if (color_id == "orange") return id(orange);
|
|
if (color_id == "red") return id(red);
|
|
if (color_id == "green") return id(green);
|
|
if (color_id == "grey") return id(grey);
|
|
return esphome::Color::WHITE; // Default color if no match
|
|
};
|
|
|
|
esphome::Color labelcolor_script = get_color(labelcolor);
|
|
esphome::Color valuecolor_script = get_color(valuecolor);
|
|
esphome::Color unitcolor_script = get_color(unitcolor);
|
|
|
|
// Resolve font objects based on the provided font IDs.
|
|
// These objects will later be used to measure text dimensions and render text on the display.
|
|
auto *labelfont_obj = get_font(labelfont);
|
|
auto *valuefont_obj = get_font(valuefont);
|
|
auto *unitfont_obj = get_font(unitfont);
|
|
|
|
// Format the numeric value as a string with the specified number of decimals.
|
|
// snprintf safely formats the float into a fixed-width character buffer.
|
|
char value_str[40];
|
|
// Check if valuestr is not empty
|
|
if (valuestr.empty()) { // Check if valuestr has any content
|
|
snprintf(value_str, sizeof(value_str), "%.*f", decimals, valuenum);
|
|
} else {
|
|
// If valuestr is empty, copy a default or alternative string into value_str
|
|
strncpy(value_str, valuestr.c_str(), sizeof(value_str)); // Example default value
|
|
value_str[sizeof(value_str) - 1] = '\0'; // Ensure null-termination
|
|
}
|
|
|
|
// Helper function to calculate text dimensions.
|
|
// This lambda takes a font object and a text string as input,
|
|
// and it calculates the text's width and height (returned via reference parameters).
|
|
auto calculate_text_dimensions = [](esphome::font::Font *font, const char *text, int &width, int &baseline) {
|
|
int x_offset = 0, height = 0;
|
|
font->measure(text, &width, &x_offset, &baseline, &height);
|
|
};
|
|
|
|
// Calculate the dimensions of the label text.
|
|
int label_width = 0, label_height = 0;
|
|
calculate_text_dimensions(labelfont_obj, label.c_str(), label_width, label_height);
|
|
|
|
// Calculate the dimensions of the value text.
|
|
int value_width = 0, value_height = 0;
|
|
calculate_text_dimensions(valuefont_obj, value_str, value_width, value_height);
|
|
|
|
// Calculate the dimensions of the unit text.
|
|
int unit_width = 0, unit_height = 0;
|
|
calculate_text_dimensions(unitfont_obj, unit.c_str(), unit_width, unit_height);
|
|
|
|
if (align == "TOP_RIGHT" ){
|
|
// Render the label on the display at the specified position (x, y).
|
|
id(main_display).printf(x, y, labelfont_obj, labelcolor_script, TextAlign::TOP_RIGHT, "%s", label.c_str());
|
|
|
|
// Render the value below the label with a vertical offset equal to the label's height.
|
|
id(main_display).printf(x - unit_width, y - 2 + label_height , valuefont_obj, valuecolor_script, TextAlign::TOP_RIGHT, "%s", value_str);
|
|
|
|
// Render the unit text to the right of the value text with appropriate offsets.
|
|
id(main_display).printf(x, y - 2 + label_height + value_height - unit_height, unitfont_obj, unitcolor_script, TextAlign::TOP_RIGHT, "%s", unit.c_str());
|
|
} else if (align == "TOP_CENTER" ){
|
|
// Calculate the maximum width of the display item, being the label or value+unit
|
|
// subtract half of that from the anchor point and position based on top left corner of the text fields
|
|
int offset = (std::max(label_width, value_width + unit_width) + 1) / 2;
|
|
|
|
// Render the label on the display at the specified position (x, y).
|
|
id(main_display).printf(x - offset, y, labelfont_obj, labelcolor_script, TextAlign::TOP_LEFT, "%s", label.c_str());
|
|
|
|
// Render the value below the label with a vertical offset equal to the label's height.
|
|
id(main_display).printf(x - offset, y - 2 + label_height , valuefont_obj, valuecolor_script, TextAlign::TOP_LEFT, "%s", value_str);
|
|
|
|
// Render the unit text to the right of the value text with appropriate offsets.
|
|
id(main_display).printf(x - offset + value_width, y -2+ label_height + value_height - unit_height, unitfont_obj, unitcolor_script, TextAlign::TOP_LEFT, "%s", unit.c_str());
|
|
} else {
|
|
// Render the label on the display at the specified position (x, y).
|
|
id(main_display).printf(x, y, labelfont_obj, labelcolor_script, TextAlign::TOP_LEFT, "%s", label.c_str());
|
|
|
|
// Render the value below the label with a vertical offset equal to the label's height.
|
|
id(main_display).printf(x, y - 2 + label_height , valuefont_obj, valuecolor_script, TextAlign::TOP_LEFT, "%s", value_str);
|
|
|
|
// Render the unit text to the right of the value text with appropriate offsets.
|
|
id(main_display).printf(x + value_width, y - 2 + label_height + value_height - unit_height , unitfont_obj, unitcolor_script, TextAlign::TOP_LEFT, "%s", unit.c_str());
|
|
}
|
|
|
|
|