Open ha88rgc opened 1 year ago
Hi
This project is in kind of a limbo as I would like to return to it some day but a little mini me is heavily limiting my time :D
Anyway, if you're stuck on loading screen, that means your device either can't connect to wifi or to home assistant. Since you mentioned that you added credentials (I assume it's wifi credentials), did you add the device to home assistant under Integrations?
Hey, thanks for the quick reply!
Yeah, it's a great project!!! Thanks a lot for this. I hope you can build on it in the future! I added an encryption key to the API, which is apparently better and works better with the recent HA update. It's successfully connected to HA and I can see the text-sensors (wifi, etc) I added
# Enable Home Assistant API
api:
encryption:
key: XXXX
I'm now seeing the clock screensaver and not just the loading bar, and when I turn the rotary
it goes to a show_value screen that6 shows 69.40 (which is the correct temperature from the HA sensor) and says verbatim show_value
. I guess that is a step forward.
The rotary only goes back and forth between the screensaver and the show_value
screen. The rotary button
does not do anything, neither does button_1
...
Where do I go from here? I.e. why are the buttons not doing anything?
So the reason why your buttons are not doing anything is that you didn't assign any action to any of them. In clock screensaver mode you can assign separate action to both encoder press and button press, which is in this section:
Once you're in the menu itself every item has (or doesn't have) action associated with it when you press the button. What you have setup is just a simple value display (for the bed temp) and value display has no action associated (since there is nothing you can do with a sensor, it can't be modified).
If you use any other action, the encoder press will take action: For Submenu, it will take you to the submenu (and button will take you back to previous level) For any of the Continuous or Binary it will take you to a screen where you can set the value via encoder (and button takes you back) For Action button pressing the encoder will perform the action. Additionally the button always acts as back button, so it takes you out of action screen, out of submenu and in the main level it takes you to screensaver
@mikosoft83 thanks a lot!! I'll check that out!
Hey @mikosoft83 I have a 'somewhat' working example now.
I included a brightness portion into the code just for a single light for testing. The display shows it and I can see the brightness value and the bar (not filled).
The only weird thing is that when I use the HA sensor that is output by the menu generator then the ESP logs say that it can't show/use "255"
for example because it's a string.
More recent changes to HA let you pull in the attribute of an entity directly, so that's what I did leaving all the other naming conventions the same so it wouldn't mess up the config.
I can see the value now, the only weird thing is that when I go on the brightness page with the lamp on, it gets turned off and when the lamp isn't on, then there is no state, i.e. no brightness (I assume that is expected and maybe necessitates a toggle screen to first turn the lamp on?)
# Sensors from Home Assistant
- platform: homeassistant
name: "HA sensor sensor.pithy_light_bar1_brightness"
entity_id: light.bar1 #sensor.pithy_light_bar1_brightness
attribute: brightness
id: light_bar1_brightness
internal: true
on_value:
then:
# Logic to correctly update menu values
- script.execute: menu_values
- if:
condition:
lambda: 'return id(menu_set_mode);'
then:
- script.execute: menu_set_rotary
Anyway, maybe using attributes directly could be a cool feature in the future. Full config below if you have any insights as to why it's just switching off the lamp instead of using the brightness value that is sent for it to be manipulated.
### Pithy Screen Menu System for controlling Home Assistant
###
### Created by: Milan Korenica
### Licensed under GNU General Public License v3.0
esphome:
name: ${unitName}
platform: ${boardPlatform}
board: ${boardName}
#set default for rotary
on_boot:
priority: 250
then:
- sensor.rotary_encoder.set_value:
id: rotary_dial
value: 0
- binary_sensor.template.publish:
id: api_connected
state: OFF
- wait_until:
api.connected
- sensor.rotary_encoder.set_value:
id: rotary_dial
value: 0
- binary_sensor.template.publish:
id: api_connected
state: ON
wifi:
ssid: !secret wifi_ssid # Enter your WiFi SSID here. Example: `ssid: 'your_network_name'`
password: !secret wifi_password # Enter your wifi password here. Example: `password: 'abcde123456'`
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: pithy
password: pithypithy
captive_portal:
# Enable logging
logger:
# Enable Home Assistant API
api:
encryption:
key: !secret pithyKey
ota:
password: pithy
#####
##### CONFIGURATION BLOCK HERE
#####
substitutions:
boardPlatform: ESP8266
boardName: d1_mini
unitName: pithy_
friendlyName: Pithy
encoderPinA: D5
encoderPinB: D6
encoderSwitch: D7
i2cData: D1
i2cClock: D2
button: D8
# Menu system
menuDepth: '1'
menuSize: '3'
##### END OF CONFIGURATION BLOCK
text_sensor:
- platform: version
hide_timestamp: true
name: "${friendlyName} ESPHome Version"
entity_category: diagnostic
- platform: wifi_info
ip_address:
name: "${friendlyName} IP Address"
icon: mdi:wifi
entity_category: diagnostic
ssid:
name: "${friendlyName} Connected SSID"
icon: mdi:wifi-strength-2
entity_category: diagnostic
globals:
# Screensaver
- id: ss_x
type: signed char
initial_value: '0'
- id: ss_y
type: signed char
initial_value: '8'
- id: ss_vx
type: signed char
initial_value: '1'
- id: ss_vy
type: signed char
initial_value: '1'
- id: wi
type: unsigned char
initial_value: '0'
# Blank screen
- id: s_blank
type: bool
initial_value: 'false'
# Menu helpers
- id: menu_max_level
type: unsigned char
initial_value: '${menuDepth}'
- id: menu_level
type: unsigned char
- id: menu_position
type: unsigned char[${menuDepth}]
- id: menu_parent
type: unsigned char[${menuDepth}]
- id: menu_current_node
type: unsigned char
- id: menu_current_label
type: char *
- id: menu_current_value
type: float
- id: menu_set_mode
type: bool
initial_value: 'false'
#####
##### CONFIGURATION BLOCK HERE
#####
# Set these to labels you want to display
- id: menu_labels
type: char * [${menuSize}]
initial_value: '{"Saver","Bed temp","Brightness"}'
# Set these to functions of particular menu items
- id: menu_functions
type: unsigned char[${menuSize}]
initial_value: '{0,1,3}'
# For submenu items, what are the children?
- id: menu_child
type: unsigned char[${menuSize}]
initial_value: '{0,0,0}'
# How many items are there for each submenu? For continuous settings, what is the range?
- id: menu_length
type: unsigned char[${menuSize}]
initial_value: '{3,0,255}'
script:
# What value to display for each menu item
- id: menu_values
then:
- lambda: |-
switch(id(menu_current_node)) {
case 1: id(menu_current_value) = id(sensor_bed_temperature).state; break;
case 2: id(menu_current_value) = id(light_bar1_brightness).state; break;
}
# What value to set rotary encoder to for each menu item setting
- id: menu_set_rotary
then:
- lambda: |-
switch(id(menu_current_node)) {
case 2: id(rotary_dial).set_value(round(id(light_bar1_brightness).state)); break;
}
# Actions for each menu item setting
- id: menu_actions
then:
- if:
condition:
lambda: 'return id(menu_current_node) == 2;'
then:
homeassistant.service:
variables:
x: 'return id(rotary_dial).state;'
service: light.turn_on
data_template:
entity_id: light.bar1
brightness: '{{ x }}'
# Action when dial is pressed on screensaver screen
- id: dial_ss_press
then:
# Action when button is pressed on screensaver screen
- id: button_1_ss_press
then:
##### END OF CONFIGURATION BLOCK
- id: ss_timeout
mode: restart
then:
- delay: 1min
- lambda: >-
id(menu_level) = 0;
id(menu_position)[0] = 0;
id(menu_parent)[0] = 0;
id(menu_current_node) = 0;
id(menu_set_mode) = false;
id(rotary_dial).set_value(0);
interval:
# Screen saver logic & wait indicator
- interval: 0.2s
then:
- lambda: |-
id(ss_x) += id(ss_vx);
id(ss_y) += id(ss_vy);
if(id(ss_x)>45 || id(ss_x)<1) id(ss_vx) *= -1;
if(id(ss_y)>29 || id(ss_y)<6) id(ss_vy) *= -1;
id(wi) = ++id(wi) > 15 ? 0 : id(wi); // wait indicator logic
i2c:
sda: ${i2cData}
scl: ${i2cClock}
frequency: 200kHz
scan: True
id: bus_a
time:
- platform: homeassistant
id: ha_time
font:
- file: "fonts/OpenSans-Regular.ttf"
id: big_font
size: 31
glyphs: ":0123456789"
- file: "fonts/OpenSans-Light.ttf"
id: small_font
size: 19
glyphs: ">-:/&!°0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz ._"
- file: "fonts/OpenSans-Light.ttf"
id: tiny_font
size: 12
glyphs: ":0123456789Conectig."
display:
- platform: ssd1306_i2c
model: "SH1106 128x64"
address: 0x3C
update_interval: 0.1s
id: idisplay
lambda: |-
if (!id(api_connected).state){
// Little animation before API is online
it.line(56, 32, 56+id(wi), 32);
} else {
// Blank screen if PIR off
if (id(s_blank)) { it.fill(COLOR_OFF); return; }
// Screensaver is always node 0
if(id(menu_current_node)==0) {
// Bouncy time
it.strftime(id(ss_x), id(ss_y), id(big_font), "%H:%M", id(ha_time).now());
}
else {
// Header time
it.strftime(0, 6, id(tiny_font), COLOR_ON, TextAlign::CENTER_LEFT, "%H:%M", id(ha_time).now());
// Header wifi
for(int i=0; i<5; i++) if(i<id(wifistep).state) it.filled_rectangle(102+i*5,8-i*2,4,i*2+4); else it.rectangle(102+i*5,8-i*2,4,i*2+4);
// Header menu level
if(id(menu_level)>0){
// y-ccord start of the level display
int b = 64 - (4 * id(menu_level));
for(int i=0; i<id(menu_level); i++) {
// Start of this symbol
int itb = b + i*8;
// Top line
it.line(itb, 2, itb+6, 6);
// Bottom line
it.line(itb+6, 6, itb, 10);
};
}
// Footer menu position
// y-coord start of the menu pos display
int b = 64 - (2 * id(menu_length)[id(menu_parent)[id(menu_level)]]);
for(int i=0; i<id(menu_length)[id(menu_parent)[id(menu_level)]]; i++) {
// Start of this symbol
int itb = b + i*4;
if(id(menu_position)[id(menu_level)] == i) it.filled_rectangle(itb, 61, 3, 3);
else it.draw_pixel_at(itb+1, 62);
};
// Show label
bool s = !id(menu_set_mode) &&
(id(menu_functions)[id(menu_current_node)] == 2 ||
id(menu_functions)[id(menu_current_node)] == 3 ||
id(menu_functions)[id(menu_current_node)] == 4 ||
id(menu_functions)[id(menu_current_node)] == 6 );
it.printf(64, 33, id(small_font), TextAlign::TOP_CENTER, "%s%s", id(menu_labels)[id(menu_current_node)], s ? " >" : "" );
// Show value
if(id(menu_set_mode)) {
switch(id(menu_functions)[id(menu_current_node)]){
case 3:
case 6:
// Value
it.printf(127, 12, id(small_font), TextAlign::TOP_RIGHT, "%.2f", id(menu_current_value));
// Setting progressbar, outline rectangle
it.rectangle(0, 20, 54, 12);
// Inner fill
it.filled_rectangle(2, 22, round(id(rotary_dial).state*0.50), 8);
break;
case 4:
// Labels
it.printf(42, 12, id(small_font), TextAlign::TOP_RIGHT, "Off");
it.printf(86, 12, id(small_font), TextAlign::TOP_LEFT, "On");
// Switch, outline rectangle
it.rectangle(52, 20, 24, 12);
// Inner toggle
it.filled_rectangle(54 + id(rotary_dial).state*10, 22, 10, 8);
}
} else {
// Show value only if Display or Setting
switch(id(menu_functions)[id(menu_current_node)]){
case 1:
case 3:
case 6:
it.printf(64, 12, id(small_font), TextAlign::TOP_CENTER, "%.2f", id(menu_current_value));
break;
case 4:
case 7:
it.printf(64, 12, id(small_font), TextAlign::TOP_CENTER, "%s", id(menu_current_value) == 0 ? "Off" : "On");
break;
case 5: // show button
it.rectangle(52, 19, 24, 14);
if(id(rotary_dial_push).state == 0){
// horizontal shades
it.line(53, 20, 73, 20);
it.line(54, 31, 72, 31);
// vertical shades
it.line(53, 20, 53, 30);
it.line(74, 21, 74, 29);
}
break;
}
}
}
}
sensor:
- platform: rotary_encoder
id: rotary_dial
pin_a:
number: ${encoderPinA}
inverted: true
mode: INPUT_PULLUP
pin_b:
number: ${encoderPinB}
inverted: true
mode: INPUT_PULLUP
filters:
- lambda: |-
unsigned char a;
if(id(menu_set_mode)) { //if set mode, rotary should go from 0 to according setting
switch(id(menu_functions)[id(menu_current_node)]){
case 3:
case 6:
a = id(menu_length)[id(menu_current_node)] + 1; break; // continuous
case 4: a = 2; break; // binary
}
} else { //if not, it should go to level length
//get current menu length
a = id(menu_length)[id(menu_parent)[id(menu_level)]];
}
//if rotary is over length, set to length
if(x >= a) {
id(rotary_dial).set_value(a-1);
return a-1;
}
else return x;
- debounce: 0.02s
resolution: 1
min_value: 0
on_value:
then:
- if:
condition:
api.connected
then:
- if:
condition:
# Are we setting or browsing?
lambda: 'return id(menu_set_mode);'
then:
# Change setting only if not in continuous + confirm
- if:
condition:
lambda: 'return !(id(menu_functions)[id(menu_current_node)] == 6);'
then:
- script.execute: menu_actions
else:
# Browsing mode, set menu position
- lambda: |-
//set current node to start of current child + rotary position
id(menu_current_node) = id(menu_child)[id(menu_parent)[id(menu_level)]] + x;
//set current level position
id(menu_position)[id(menu_level)] = x;
# Update value
- script.execute: menu_values
- script.execute: ss_timeout
- platform: wifi_signal
id: wifisignal
update_interval: 20s
- platform: template
id: wifistep
update_interval: 20s
lambda: |-
if(isnan(id(wifisignal).state)) return 0;
else return round((id(wifisignal).state+100)/10);
# - platform: sht3xd
# temperature:
# name: "${friendlyName} Temperature"
# id: ${unitName}_temperature
# filters:
# - offset: -4
# on_value:
# then:
# # Logic to correctly update menu values
# - script.execute: menu_values
# - if:
# condition:
# lambda: 'return id(menu_set_mode);'
# then:
# - script.execute: menu_set_rotary
# # End of menu values logic
# humidity:
# name: "${friendlyName} Humidity"
# id: ${unitName}_humidity
# on_value:
# then:
# # Logic to correctly update menu values
# - script.execute: menu_values
# - if:
# condition:
# lambda: 'return id(menu_set_mode);'
# then:
# - script.execute: menu_set_rotary
# # End of menu values logic
# address: 0x44
# update_interval: 15s
#####
##### CONFIGURATION BLOCK HERE
#####
# Sensors from Home Assistant
- platform: homeassistant
name: "HA sensor sensor.pithy_light_bar1_brightness"
entity_id: light.bar1 #sensor.pithy_light_bar1_brightness
attribute: brightness
id: light_bar1_brightness
internal: true
on_value:
then:
# Logic to correctly update menu values
- script.execute: menu_values
- if:
condition:
lambda: 'return id(menu_set_mode);'
then:
- script.execute: menu_set_rotary
# End of menu values logic
- platform: homeassistant
name: "Bed Temp"
id: sensor_bed_temperature
entity_id: sensor.bed_temperature
##### END OF CONFIGURATION BLOCK
binary_sensor:
- platform: gpio
id: rotary_dial_push
pin:
number: ${encoderSwitch}
inverted: true
mode: INPUT_PULLUP
on_press:
then:
- if:
condition:
api.connected
then:
# Execute screensaver action
- if:
condition:
lambda: 'return id(menu_current_node) == 0;'
then:
script.execute: dial_ss_press
- if:
condition:
# Execute continuous setting with confirmation when returning from set mode
lambda: 'return id(menu_functions)[id(menu_current_node)] == 6 && id(menu_set_mode) == true;'
then:
- script.execute: menu_actions
- if:
condition:
# Set mode for continuous or binary setting
lambda: 'return (id(menu_functions)[id(menu_current_node)] == 3 || id(menu_functions)[id(menu_current_node)] == 4 || id(menu_functions)[id(menu_current_node)] == 6);'
then:
- lambda: |-
//toggle set mode
if(id(menu_set_mode)) {
id(menu_set_mode) = false;
// restore rotary value to position
id(rotary_dial).set_value(id(menu_position)[id(menu_level)]);
} else id(menu_set_mode) = true;
- if:
condition:
# Button action
lambda: 'return id(menu_functions)[id(menu_current_node)] == 5;'
then:
- script.execute: menu_actions
# If set mode, set rotary
- if:
condition:
lambda: 'return id(menu_set_mode);'
then:
- script.execute: menu_set_rotary
- if:
condition:
# Go to submenu. This needs to be last to prevent setting new item and also executing it
lambda: 'return id(menu_functions)[id(menu_current_node)] == 2;'
then:
- lambda: |-
//raise level up to max level
id(menu_level) = ++id(menu_level) > id(menu_max_level) ? id(menu_max_level) : id(menu_level);
//set parent node for new level
id(menu_parent)[id(menu_level)] = id(menu_current_node);
//set new current node
id(menu_current_node) = id(menu_child)[id(menu_parent)[id(menu_level)]];
//reset rotary to 0
id(rotary_dial).set_value(0);
//reset position in current level to 0
id(menu_position)[id(menu_level)] = 0;
# Display entities value for each menu item
- script.execute: menu_values
- script.execute: ss_timeout
- platform: gpio
id: button_1
pin:
number: ${button}
inverted: true
mode: INPUT_PULLUP
on_press:
then:
# Execute screensaver action
- if:
condition:
and:
- lambda: 'return id(menu_current_node) == 0;'
- api.connected
then:
script.execute: button_1_ss_press
- lambda: |-
if(id(menu_set_mode)) {
id(menu_set_mode) = false;
id(rotary_dial).set_value(id(menu_position)[id(menu_level)]);
}
else {
if(id(menu_level) > 0) { //if we have anywhere to return
//set new current node to current parent
id(menu_current_node) = id(menu_parent)[id(menu_level)];
//return to previous level
--id(menu_level);
//reset rotary to position for current level
id(rotary_dial).set_value(id(menu_position)[id(menu_level)]);
} else {
if(id(menu_level) == 0) { //if we are at level 0, jump to saver
//set new current node to 0
id(menu_current_node) = 0;
//reset rotary to 0
id(rotary_dial).set_value(0);
//reset menu position for current level to 0
id(menu_position)[id(menu_level)] = 0;
} } }
- script.execute: ss_timeout
- platform: template
id: api_connected
#####
##### CONFIGURATION BLOCK HERE
#####
# Binary sensors from HomeAssistant
##### END OF CONFIGURATION BLOCK
To be honest, when I did the version of the script you're using I didn't yet have a dimmable lamp so I just did it on assumption how brightness works. I do have a dimmer now so I also noticed there is no brightness attribute once lamp is off. That probably messes up the ESP code, I don't know what value the sensor gets if there is no attribute. Using the attributes directly is on my (long standing) todo list. Actually, the attribute support in ESPhome is partly a result of the whole Pithy project of which I was a part and yet I never found time to actually implement it to my code. I do have a working code for attributes for another device that uses a LED ring instead of display and it shouldn't be that difficult to reuse it (it's the same code for the most part) but again, time is the enemy. It's mostly about "details" such as config import that needs to be most heavily reworked for the new code.
Anyway, one thing that you can try is change this block like this:
- id: menu_actions
then:
- if:
condition:
lambda: 'return id(menu_current_node) == 2;'
then:
homeassistant.service:
variables:
x: 'stoi(return id(rotary_dial).state);'
service: light.turn_on
data_template:
entity_id: light.bar1
brightness: '{{ x }}'
Change is in this line of your config:
x: 'return id(rotary_dial).state;'
In my version it should convert the string to integer. Why it passes the brightness value as string I have no idea but once I get to it I'll check it out with my dimmer.
Hey @mikosoft83 thanks a lot for your input!
I tried 'x: stoi(return id(rotary_dial).state);'
and x: 'std::stoi(return (id(rotary_dial).state));' ##FAILS
this fails with the following error :
pithy_screen_withsubmenu.yaml:193:17: error: expected primary-expression before 'return'
src/esphome/core/automation.h:33:3: error: 'esphome::TemplatableValue<T, X>::TemplatableValue(F) [with F = esphome::api::TemplatableStringValue<X>::TemplatableStringValue<setup()::<lambda()>, 0>::<lambda()>; typename std::enable_if<std::is_invocable<F, X ...>::value, int>::type <anonymous> = 0; T = std::__cxx11::basic_string<char>; X = {}]', declared using local type 'esphome::api::TemplatableStringValue<X>::TemplatableStringValue<setup()::<lambda()>, 0>::<lambda()>', is used but never defined [-fpermissive]
Any suggestions are greatly appreciated! I added std::
as well because not having it initially threw a different error. I assume error: expected primary-expression before 'return'
means that somethings is referenced but not in the code?
One potential bug I found with a simple fix: In the glyphs
below, the _
was missing, which threw an error reading/showing the numbers from the Display Value
menu. Just thought you might want to make a note of that.
- file: "fonts/OpenSans-Light.ttf"
id: small_font
size: 19
glyphs: ">-:/&!°0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz ._"
When you do get some time to do more dev on this project, I'd be happy to help QA and see if stuff breaks!
Interesting bit about that underscore. I wonder why would a number need an underscore? Maybe there lies the culprit. Can you please show me the value of whatever you're trying to display?
@mikosoft83 I don't know. In the first pic, you can see test-value
which is what I named it, before it was show_value
and that wouldn't work. The current version, thus, probably doesn't need the _
. The actual sensor value from HA is displaying correctly in the show value menu.
The brightness value, however, is not pulling in when set to sensor.pithy_light_bar1_brightness
in ESPHome.
HA config
- platform: template
sensors:
pithy_light_bar1_brightness:
value_template: >
"{{ (state_attr('light.bar1', 'brightness') | int) | round(0)}}"
#value_template: "{{ (states.light.bar1.attributes.brightness) | int }}"
Currently, I'm getting the error(s) mentioned above because of 'x: stoi(return id(rotary_dial).state);'
or 'x: 'std::stoi(return (id(rotary_dial).state));'
. Everything else works fine, i.e. Value Display, Toggle, Action button.
With
- platform: homeassistant
name: "HA sensor sensor.pithy_light_bar1_brightness"
entity_id: light.bar1 #sensor.pithy_light_bar1_brightness
attribute: brightness
id: light_bar1_brightness
internal: true
on_value:
then:
# Logic to correctly update menu values
- script.execute: menu_values
- if:
condition:
lambda: 'return id(menu_set_mode);'
then:
- script.execute: menu_set_rotary
I'm getting the brightness value pulled in 255.00
However, the actual manipulation of the value doesn't work. But, pressing the rotary button again here, will set the brightness to 0 and turn the lamp off. When I turn the rotary, the log doesn't show any values, just
[09:14:33][D][sensor:126]: 'rotary_dial': Sending state -1.00000 steps with 0 decimals of accuracy
[09:14:33][D][script:077]: Script 'ss_timeout' restarting (mode: restart)
[09:14:33][D][sensor:126]: 'rotary_dial': Sending state -1.00000 steps with 0 decimals of accuracy
[09:14:33][D][script:077]: Script 'ss_timeout' restarting (mode: restart)
[09:14:35][D][sensor:126]: 'rotary_dial': Sending state -1.00000 steps with 0 decimals of accuracy
[09:14:35][D][script:077]: Script 'ss_timeout' restarting (mode: restart)
Okay, that was stupid of me. The correct fix for the line is
x: 'return stoi(id(rotary_dial).state);'
Try with that and let me know although I'm still baffled why would the state of the rotary encoder be a string.
It seems to me the brightness sensor doesn't handle well the fact that there is no brightness attribute when turned off. Can you turn on the light in other way and watch what you see in the ESPhome device log when it turns on and off?
@mikosoft83 Thanks! Okay, so when I have this
- platform: homeassistant
name: "HA sensor sensor.pithy_light_bar1_brightness"
entity_id: sensor.pithy_light_bar1_brightness
id: light_bar1_brightness
internal: true
on_value:
then:
# Logic to correctly update menu values
- script.execute: menu_values
- if:
condition:
lambda: 'return id(menu_set_mode);'
then:
- script.execute: menu_set_rotary
In the sensor section, and
variables:
x: 'return (id(rotary_dial).state);'
in the menu options, the display shows nan
for the brightness value. The log-output then says [W][homeassistant.sensor:015]: Can't convert '"255"' to number!
when I use anything else in the menu options, i.e. x: 'return stoi(id(rotary_dial).state);'
or x: 'return stoi(id(rotary_dial).state);'
or x: 'return std::stoi(id(rotary_dial).state);'
I get a bunch of errors in the logs, for example
pithy_screen_withsubmenu.yaml: In function 'void setup()':
pithy_screen_withsubmenu.yaml:966:60: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
pithy_screen_withsubmenu.yaml:966:68: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
pithy_screen_withsubmenu.yaml:966:81: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
pithy_screen_withsubmenu.yaml:966:94: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
pithy_screen_withsubmenu.yaml:966:108: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
pithy_screen_withsubmenu.yaml:966:119: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
pithy_screen_withsubmenu.yaml:966:134: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
pithy_screen_withsubmenu.yaml: In lambda function:
pithy_screen_withsubmenu.yaml:193:43: error: no matching function for call to 'stoi(float&)'
In file included from /home/mraess/.platformio/packages/toolchain-xtensa/xtensa-lx106-elf/include/c++/10.3.0/string:55,
from src/esphome/components/socket/socket.h:2,
from src/esphome/components/api/api_frame_helper.h:13,
from src/esphome/components/api/api_connection.h:3,
from src/esphome.h:3,
from src/main.cpp:3:
I'm wondering if there isn't a way to send the value from HA as an integer directly?
The other thing is that when I'm in the actual brightness menu (with the bar), then the rotary doesn't actually produce any values in the logs but rather seems to time out and reset itself??
[18:47:06][D][script:077]: Script 'ss_timeout' restarting (mode: restart)
[18:47:06][D][binary_sensor:036]: 'rotary_dial_push': Sending state OFF
You can try "atoi" instead of "stoi" Or you can remove the "stoi" from the menu script and add filter to the sensor:
- platform: homeassistant
name: "HA sensor sensor.pithy_light_bar1_brightness"
entity_id: sensor.pithy_light_bar1_brightness
...
filters:
- lambda: return atoi(x);
...
Also yes, apparently the value is sent as string and when the old method of using template sensors was used it got converted to integer in template. Seems like a bug in HA and apparently it's been 2 years and it's not fixed.
@mikosoft83 Thanks a lot for all your input! I've tried that as well and it didn't work :( I'll dabble around some more and report back.
HA and apparently it's been 2 years and it's not fixed That seems like an easier bug to fix and quite an important one. I'll try to somehow send the value out of HA as an int and report back.
@mikosoft83 so unfortunately non of the permutations of stoi
, std:stoi
, atoi
, or std:atoi
worked. I have managed a simple setup where the brightness level of the lamp is at least shown in the display (see pics below), by using the entity light.bar1
directly with the attribute brightness
. However, as soon as I go into the menu the light turns off immediately (see second pic) because it seems the rotary is not set to the actual value coming in. Could this be because it shows as a float
instead of int
?
- platform: homeassistant
name: "HA sensor sensor.pithy_light_bar1_brightness"
entity_id: light.bar1
attribute: brightness
filters:
- lambda: return x;
id: light_bar1_brightness
internal: true
on_value:
then:
# Logic to correctly update menu values
- script.execute: menu_values
- if:
condition:
lambda: 'return id(menu_set_mode);'
then:
- script.execute: menu_set_rotary
# End of menu values logic
Any changes to the filter in the above code, such as lambda: return atoi(x)
didn't work and caused errors during compile.
Could this portion
- id: menu_set_rotary
then:
- lambda: |- # for some reason the rotary is not set to the right value maybe because it's float instead of int??
switch(id(menu_current_node)) {
case 2: id(rotary_dial).set_value(round(id(light_bar1_brightness).state)); break;
}
be the reason for why the rotary value isn't updated?
That would be a weird behavior. It's true that the value is float but it's rounded in the rotary assignment and should get cast to int. If you wish you can try to cast it manually but it probably won't make much difference:
case 2: id(rotary_dial).set_value((int)round(id(light_bar1_brightness).state)); break;
@mikosoft83 yeah that didn't work either unfortunately. The rotary doesn't respond at all in this menu.
I'll have to try this with my light one day but as I mentioned my time is extremely limited nowadays :/
@mikosoft83 I hear you! Thanks for sticking with me for so long haha. Please let me know once you figure it out with your light.
@mikosoft83 one more question. What would I have to do to show a pic as the screensaver similar to the original ioios code?
To be honest I haven't used pictures in ESPHome. So I guess look up how John dislays the picture in his code and then replace this line in my code with his (it's under the display lambda):
// Bouncy time
it.strftime(id(ss_x), id(ss_y), id(big_font), "%H:%M", id(ha_time).now());
If you want the pic to bounce around like my clock you can use the id(ss_x), id(ss_y) as coordinates but you need to fix the limits in this code:
interval:
# Screen saver logic & wait indicator
- interval: 0.2s
then:
- lambda: |-
id(ss_x) += id(ss_vx);
id(ss_y) += id(ss_vy);
if(id(ss_x)>45 || id(ss_x)<1) id(ss_vx) *= -1;
if(id(ss_y)>29 || id(ss_y)<6) id(ss_vy) *= -1;
id(wi) = ++id(wi) > 15 ? 0 : id(wi); // wait indicator logic
Numbers 45 and 29 are the rightmost and lowermost limits respectively of where the content (in my case clock) can go before it "bounces" back.
@mikosoft83 Thanks, I'll have to check that out.
Hello,
In hopes that is is still maintained, I'm reaching out for some advice. I generated a minimal example with the menu generator and filled in my creds, etc. It is running on an ESP8266 dev board with rotary encoder attached as well as an external button at D8. The SHT and PIR are not included and I commented-out those code sections.
Unfortunately, all I can see on the screen is the screensaver loading bar. The
rotary push button
responds in the log output. Therotary
itself only returns 0 or 1.button_1
does not respond.Any advice/insights on what I'm missing here to get a minimal example set up (see config below)? Any help would be greatly appreciated!