#Dynamic cover button
1 messages ยท Page 1 of 1 (latest)
Add something like yaml variables: var_entity: cover.hall_coverThen where you have 'cover.hall_cover', replace it with variables.var_entity (no quotation marks around it) for the icon and styles sections.
Do your blinds have "tilt" capabilies?
no, they are just basic roller blinds
I cant post anymore code.. reach character limit ๐ฆ
so the top part of my code should be:
type: custom:button-card variables: var_entity: cover.hall_cover show_state: true name: Hall Blind
What does the position attribute report if the blinds are closed? Is it 0?
0
No, you still need to keep the entity in there. But... I'm stupid and over looked something way easier...
so like this?
type: custom:button-card entity: cover.hall_cover variables: var_entity: cover.hall_cover show_state: true name: Hall Blind icon: |- [[[
custom:button-card has a built-in entity variable. Leave this the way it is yaml type: custom:button-card entity: cover.hall_cover show_state: true name: Hall Blindbut you can change,
(states['cover.hall_cover'].state == "open")``` to ```yaml
(states[entity].state == "open")```
ah yes, good eye there!
so I dont need to use the
variables: var_entity: cover.hall_cover
anymore?
No. Not at this point since you're going to use the card's entity variable.
right great! this does make it easier to migrate to another blind
Yeah. That's going to be useful later, too, when (if) you migrate to a configuration template which will cut down on code and updating cards.
And actually, I'm going to copy all your code and use one of my demo entities at the same time.
hmm doesnt work. its probably the square brackets.
The state can be returned with simple entity.state
it has to be [entity.state]
Okay. Think I have everything copied on my side. The 90px card height messed me up and I wasn't getting an icon...
Do your icons work the way they're defined in the code?
Nvm. Figured it out. Your entity has both position and current_position. Mine only has current_position.
Bringing your logic into the thread:
yes thats what Im trying to do. control my blinds from 1 single button. so there is some logic to it. e.g. if the blind is fully opened> close the blind. If the blind is fully closed > open the blind. IF its in the middle somewhere then depending on whether it is above or below the mid point, then open/ close accordingly.
I think, to make the code easier, everything should be based around the position of the blinds and not consider the state (open/closed) because closed=0 but open= 1 to 100.
cant seem to get the entity to work properly.. doing some troubleshooting now
I just about have it. Ran into a couple of snags but working through them. (I got it to open and close appropriately.)
this is how mine looks like
changing ((states['cover.hall_cover'].state == "open") to ((states[entity].state == "open") doesn't work
if (entity.state == "opening"){
type: custom:button-card entity: cover.hall_cover show_state: true name: Hall Blind icon: |- [[[ if ((entity.state == "open") & (entity.attributes.position > "99")){ return "mdi:blinds-open"; } else if ((entity.state == "open") & (entity.attributes.position < "100")){ return "mdi:blinds"; } else if ((entity.state == "closed") & (entity.attributes.position < "100")){ return "mdi:roller-shade-closed"; } else if (entity.state == "opening"){ return "mdi:arrow-up-bold-box"; } else if (entity.state == "closing"){ return "mdi:arrow-down-bold-box"; } ]]] styles: icon: - color: | [[[ if (entity.state == "opening"){ return "orange"; } else if (entity.state == "closing"){ return "orange"; } else if (entity.attributes.moving == "STOP"){ return "grey"; } else { return "grey"; } ]]] card: - height: 90px name: - padding-left: 3px - font-weight: bold - font-size: 13px - justify-self: middle state: - font-size: 12px - padding-top: 2px - padding-left: 3px - font-weight: bold - justify-self: middle - color: darkgrey tap_action: action: call-service service: script.hall_blinds_script hold_action: action: more-info
ok this is the working one. Now to work on tap_action
Need you to do a test for me. Add this line to you code (like under show_state: true:yaml state_display: '[[[return entity.attributes.current_position ]]]' and then move your blinds to a different position other than 100.
super weird. this whole time I have been fighting with the code, I think I have a bug somewhere. Perhaps with the Demo entities but I cannot get it to report the current_position. Always shows 100. Did notice when moving the value would change but then return to 100 even though the attribute is at something else... ๐
If you would, keep that line in there for now. I'm going to finish the code assuming that it should work and then you'll have to test on your side to be certain.
mine just shows a numerical value now instead of open or closede
Yeah. That's what I needed to see. At the end, you'll be able to get rid of that.
We're using it as a debug tool for the moment.
yeah its nice to have for me to determine the mid point value of my blind
Yeah. That's the goal. I won't be able to test on my side though.
In theory, we might be able to expand this to add a hold_action for example and move it incrementally but that may take a bit more work...
but mid point values are different when moving up and down ๐ฆ
wouldn't 50 be the midpoint?
that probably has to do with the calibration of my blind
the motors run for 60s each way until it is stopped by the limit which is hardware set
So, technically, your blinds only have an open or close? How to you stop them midway?
cover.stop?
determining exactly midway is the issue. I have to deal with the calibration first
Okay. Well, I'll to you what. I have the code that can handle opening if it is closed, and closing if it is open. We can start with that and expand at some point.
I will also use double_tab to change the direction if needed
With this code, I tried not to "step on" anything you've already written. The only change that it will need fixed is the entity:. I had to turn that into a variable in order to get it to pass in the action. I also used a double_tap_action to not interfere with your tap_ and hold_ actions that you already have. Just change the var_entity variable to your entity (cover.hall_cover).
variables:
var_service: |
[[[
var pos = entity.attributes.current_position;
if (pos == 0 ) return 'cover.open_cover';
if (pos <= 100) return 'cover.close_cover';
]]]
double_tap_action:
action: call-service
service: '[[[ return variables.var_service ]]]'
target:
entity_id: '[[[ return entity.entity_id ]]]'
I still dont understand entity: '[[[ return variables.var_entity ]]]'
wont I have to change that to fit my code?
since I already have entity defined in the beginnning>
type: custom:button-card entity: cover.hall_cover show_state: true
Yeah. Just remove your entity:, use my entity:, and set var_entity: cover.hall_cover.
This change was required to in order to make the entity_id in the target work because it would not pass as the built-in entity variable.
ok understand now. Thanks!
You could just use entity.entity_id in the target instead of writing the entity into a variable
sorry please elaborate
where do use use this entity.entity_id?
That seems to work.
type: custom:button-card entity: '[[[ return variables.var_entity ]]]' show_state: true name: Master Airwell Blind icon: |- [[[ if ((entity.state == "open") & (entity.attributes.position > "99")){ return "mdi:blinds-open"; } else if ((entity.state == "open") & (entity.attributes.position < "100")){ return "mdi:blinds"; } else if ((entity.state == "closed") & (entity.attributes.position < "100")){ return "mdi:roller-shade-closed"; } else if (entity.state == "opening"){ return "mdi:arrow-up-bold-box"; } else if (entity.state == "closing"){ return "mdi:arrow-down-bold-box"; } ]]] styles: icon: - color: | [[[ if (entity.state == "opening"){ return "orange"; } else if (entity.state == "closing"){ return "orange"; } else if (entity.attributes.moving == "STOP"){ return "grey"; } else { return "grey"; } ]]] card: - height: 90px name: - padding-left: 3px - font-weight: bold - font-size: 13px - justify-self: middle state: - font-size: 12px - padding-top: 2px - padding-left: 3px - font-weight: bold - justify-self: middle - color: darkgrey variables: var_entity: cover.master_inner_cover tap_action: action: call-service service: script.master_airwell_blinds_open hold_action: action: more-info
This btw far more cleaner and better optimized
entity: cover.hall_cover
double_tap_action:
action: call-service
service: >
[[[
var pos = entity.attributes.current_position
if (pos == 0 ) {return 'cover.open_cover';}
return 'cover.close_cover';
]]]
target:
entity_id: '[[[ return entity.entity_id ]]]'
I put them as variables for a reason for the time being. Both snippets of code work.
thanks for the input.๐๐ผ
how do you define multiple variables in javascript? e.g. var pos = entity.attributes.current_position; var stt = entity.state ?
I normally just put them on separate lines but I think separated with a semi-colon would work in the actual JavaScript. If used in the variables: field, it has to be on separate lines.
thats what really drives me nuts... not knowing these conventions=|
[[[ var pos = entity.attributes.current_position; if (pos == 0 ) return 'cover.open_cover'; if (pos <= 100) return 'cover.close_cover'; ]]]
how do you use Else if and else in javascript?
well, the card's code is handling the variables field but JavaScript within the [[[ ]]] is being processed by the browser (I think). When the card processes the variables field, it has to "follow" yaml rules.
just use else if and else.
Used in another project:yaml variables: humidity: | [[[ var humidity = states["sensor.bedroom_humidity"].state; if (humidity >= 60) return "high"; else if (humidity <= 30) return "low"; else return true ]]]
so if I define 2 variables pos and stt, is this the right way to do it: var pos = entity.attributes.position; stt = entity.state?
or var pos = entity.attributes.position; var stt = entity.state?
I think you have to use the second one, but I could have swore that the first one would have worked too but I might be thinking of a different language.
[[[ var pos = entity.attributes.position var stt = entity.state if ((stt == "closed") & (pos == 0 )) {return 'cover.open_cover';} return 'cover.close_cover'; ]]]
this works
If else with both a return can also be written with only the if like in the snippet I posted before
something: >
[[[
if(condition)
return something
return something_else
]]]
var pos = entity.attributes.position, stt = entity.state should work
So basically, the ELSE is assumed?
something: > [[[ if(condition) return something else if(condition) return something return something_else ]]]
is this correct? I have multiple conditions
I tried it but it didnt
You could say it that way, but what it does is that each template stops rendering at the first return. If the condition is true, it reads the first one, when false it skips the condition statement and reads the second on
Okay. So return is also like "break" (break out of the code and be done)
or:
something: >
[[[
if(condition)
{return something}
if(condition)
{return something_different}
return something_else
]]]
( also added brackets for readability)
doesnt this do multiple "if" statements?
This worked for me. Note that I defined pos and pos2 on the same line and used the pos2 variable for the IFs.yaml variables: var_service: | [[[ var pos = entity.attributes.current_position, pos2 = entity.attributes.current_position; if (pos2 == 0 ) return 'cover.open_cover'; if (pos2 <= 100) return 'cover.close_cover'; ]]]
Like Bas was saying, it is going to do whatever it matches as true first. If not true, then it moves on to the next. But, IFs can also be nested too.
But, if you're looking at incorporating the state to the service call variable, I do not think that is needed. That's why I mentioned working with just the position.
I had an issue with multiple Ifs. because even if the 1st one is done. it will do the 2nd if. for nested if (if, elseif, else) it will stop when it finds a condition/or not
The use of return breaks the template, if you don't use a return then it will also evaluate the next condition even though the previous one was already true
Literally right there in the definition of return.
The return statement ends function execution and specifies a value to be returned to the function caller.
And therefore optimizes the computations needed
my final config for reference
Aren't the states not based on the position?
so closed is always 0 and open is between 1 and 100
yes but there are times when the blind stops in between 0 and 100, thus I use the mid point (52) in the code to determine whether the blind should go up or go down from where it last stopped
this is really for a 1 button operation. else, how would it determine whether to go up or down?
so for positions 1 to 99, depending on whether it is above 51 or below 52, it will close and open the blinds respectively
I guess this does exactly the same
service: |
[[[
var pos = entity.attributes.position
var stt = entity.state
if (stt == "closing" || stt == "opening"){
return 'cover.stop_cover';}
if (pos < 52){
return 'cover.open_cover';}
if(pos > 51 ){
return 'cover.close_cover';}
return 'cover.stop_cover';
]]]
And the icon can also be optimized
icon: |-
[[[
var attr = entity.attributes.position
if(entity.state =='open'){
if(attr < 100){
return "mdi:blinds";
}
return "mdi:blinds-open"
}
if (entity.state == "opening"){
return "mdi:arrow-up-bold-box";
}
if (entity.state == "closing"){
return "mdi:arrow-down-bold-box";
}
return "mdi:roller-shade-closed"
]]]