Closed olympia closed 1 year ago
I'm aware of this behavior, but it's just a message that appears in the logs -- the valves should still switch at the expected times. Can you verify the valve/zone behavior is correct and elaborate on if this is causing a specific issue for you? I believe it's just a visual quirk in the logs and the valve/zone is still completing as expected/required.
From switching perspective you are completely right -- it is switching when expected.
However, it looks like the active valve (active_valve()
)within the cycle becomes the next as from this "marking point".
Please have a look at the below template sensors, where I use if(id(sprinkler_ctrl).active_valve() == 0)
and if(id(sprinkler_ctrl).active_valve() == 1)
conditions to decide into which sensor time_remaining_active_valve()
should populate the remaining time.
If you are now looking at the esphome log I shared initially, you will see that the as from the marking point (10s earlier than the end of zone) the last 10 seconds of the remaining time gets populated into Zone 2 instead of Zone 1. If I don't set any valve open delay, then all works fine and as expected.
I hope this makes sense to you... does it? :)
# Zone 1 - Define Progress percent as a sensor and publish time remaining to its time remaining text sensor
- platform: template
id: zone1_progress_percentage
name: "Sprinkler Zone 1 Progress Percentage"
update_interval: $update_freq
filters:
- delta: 1
lambda: |-
if(id(sprinkler_ctrl).active_valve() == 0) {
int seconds = round(id(sprinkler_ctrl).time_remaining_active_valve().value_or(0));
int days = seconds / (24 * 3600);
seconds = seconds % (24 * 3600);
int hours = seconds / 3600;
seconds = seconds % 3600;
int minutes = seconds / 60;
seconds = seconds % 60;
id(zone_1_time_remaining).publish_state((
(days ? String(days) + "d " : "") +
(hours ? String(hours) + "h " : "") +
(minutes ? String(minutes) + "m " : "") +
(String(seconds) + "s")
).c_str());
return ((id(sprinkler_ctrl).valve_run_duration_adjusted(0) - id(sprinkler_ctrl).time_remaining_active_valve().value_or(0)) * 100 / id(sprinkler_ctrl).valve_run_duration_adjusted(0));
}
if (id(sprinkler_ctrl).active_valve().has_value() == false && id(sprinkler_ctrl_status).state == "Idle") {
return 0;
}
else if(id(zone1_progress_percentage).state > 1 && id(sprinkler_ctrl_status).state != "Paused")
{
return 100;
}
return {};
# Zone 2 - Define Progress percent as a sensor and publish time remaining to its time remaining text sensor
- platform: template
id: zone2_progress_percentage
name: "Sprinkler Zone 2 Progress Percentage"
update_interval: $update_freq
filters:
- delta: 1
lambda: |-
if(id(sprinkler_ctrl).active_valve() == 1) {
int seconds = round(id(sprinkler_ctrl).time_remaining_active_valve().value_or(0));
int days = seconds / (24 * 3600);
seconds = seconds % (24 * 3600);
int hours = seconds / 3600;
seconds = seconds % 3600;
int minutes = seconds / 60;
seconds = seconds % 60;
id(zone_2_time_remaining).publish_state((
(days ? String(days) + "d " : "") +
(hours ? String(hours) + "h " : "") +
(minutes ? String(minutes) + "m " : "") +
(String(seconds) + "s")
).c_str());
return ((id(sprinkler_ctrl).valve_run_duration_adjusted(1) - id(sprinkler_ctrl).time_remaining_active_valve().value_or(1)) * 100 / id(sprinkler_ctrl).valve_run_duration_adjusted(1));
}
if (id(sprinkler_ctrl).active_valve().has_value() == false && id(sprinkler_ctrl_status).state == "Idle")
{
return 0;
}
else if(id(zone2_progress_percentage).state > 1 && id(sprinkler_ctrl_status).state != "Paused")
{
return 100;
}
return {};
This makes perfect sense and, while I realize it's not quite as expected, there is a very specific interval during which this condition exists and it doesn't affect the behavior of the controller itself. The reason the behavior occurs is due to the architecture of the state machine and delay interval handling -- to correct this, another set of timers and logic would be required to handle this specific situation. Call it "being lazy"...but...again...I'm curious if this is causing a specific issue for you. It appears to me that you've set up a bunch of sensors to analyze/display some of the controllers internal behavior and, while I understand what you're doing, the fix for this will be a bit involved to implement.
That said, there was some discussion around implementing an additional feature set in a future version to permit things like a maximum zone/valve run time which would likely require some re-vamping of controller's internal scheduling. If we end up proceeding down this path, this behavior will likely be corrected at that time, anyway. Any thoughts?
Indeed, I was/am about to develop a comprehensive sprinkler dashboard what is nicely displaying - as you name it - the controllers' internal behavior, providing the users a detailed view on an eye catching way.
To answer your question, this is certainly not causing any specific functional issue and I do also understand what you mean by small gain for huge efforts. I actually thought it's something easy to fix, but obviously I was ignorantly wrong... :)
I will live with this for now and looking forward to the mentioned re-vamping whenever it happens -- many thanks for your attention!
Can time_remaining_current_operation()
also somewhat defective due to the same reason when valve open delay is being used?
In the below example, I am populating "Sprinkler Controller Overall Time Remaining" by time_remaining_current_operation()
and please see that it is also misbehaving just right after the marker point.
This is with 30s valve time both for Zone 1 and 2 and 10s valve open delay.
[21:23:55][D][text_sensor:064]: 'Sprinkler Controller Overall Time Remaining': Sending state '42s'
[21:23:55][D][sensor:109]: 'Sprinkler Controller Overall Progress Percentage': Sending state 30.00000 with 1 decimals of accuracy
[21:23:56][D][text_sensor:064]: 'Sprinkler Zone 1 Time Remaining': Sending state '11s'
[21:23:56][D][sensor:109]: 'Sprinkler Zone 1 Progress Percentage': Sending state 63.00000 with 1 decimals of accuracy
[21:23:56][D][text_sensor:064]: 'Sprinkler Controller Overall Time Remaining': Sending state '41s'
[21:23:56][D][sensor:109]: 'Sprinkler Controller Overall Progress Percentage': Sending state 31.00000 with 1 decimals of accuracy
[21:23:57][D][text_sensor:064]: 'Sprinkler Zone 1 Time Remaining': Sending state '10s'
[21:23:57][D][sensor:109]: 'Sprinkler Zone 1 Progress Percentage': Sending state 66.00000 with 1 decimals of accuracy
[21:23:57][D][text_sensor:064]: 'Sprinkler Controller Overall Time Remaining': Sending state '40s'
[21:23:57][D][sensor:109]: 'Sprinkler Controller Overall Progress Percentage': Sending state 33.00000 with 1 decimals of accuracy
[21:23:57][D][sprinkler:1242]: Marking valve 0 complete
[21:23:58][D][sensor:109]: 'Sprinkler Controller Status Internal': Sending state 1.00000 with 1 decimals of accuracy
[21:23:58][D][text_sensor:064]: 'Sprinkler Zone 1 Time Remaining': Sending state '9s'
[21:23:58][D][sensor:109]: 'Sprinkler Zone 1 Progress Percentage': Sending state 70.00000 with 1 decimals of accuracy
[21:23:58][D][text_sensor:064]: 'Sprinkler Controller Overall Time Remaining': Sending state '9s'
[21:23:58][D][sensor:109]: 'Sprinkler Controller Overall Progress Percentage': Sending state 85.00000 with 1 decimals of accuracy
[21:23:59][D][text_sensor:064]: 'Sprinkler Zone 1 Time Remaining': Sending state '8s'
[21:23:59][D][sensor:109]: 'Sprinkler Zone 1 Progress Percentage': Sending state 73.00000 with 1 decimals of accuracy
[21:23:59][D][text_sensor:064]: 'Sprinkler Controller Overall Time Remaining': Sending state '8s'
[21:23:59][D][sensor:109]: 'Sprinkler Controller Overall Progress Percentage': Sending state 86.00000 with 1 decimals of accuracy
[21:24:00][D][text_sensor:064]: 'Sprinkler Zone 1 Time Remaining': Sending state '7s'
[21:24:00][D][sensor:109]: 'Sprinkler Zone 1 Progress Percentage': Sending state 76.00000 with 1 decimals of accuracy
[21:24:00][D][text_sensor:064]: 'Sprinkler Controller Overall Time Remaining': Sending state '7s'
[21:24:00][D][sensor:109]: 'Sprinkler Controller Overall Progress Percentage': Sending state 88.00000 with 1 decimals of accuracy
[21:24:01][D][text_sensor:064]: 'Sprinkler Zone 1 Time Remaining': Sending state '6s'
[21:24:01][D][sensor:109]: 'Sprinkler Zone 1 Progress Percentage': Sending state 80.00000 with 1 decimals of accuracy
[21:24:01][D][text_sensor:064]: 'Sprinkler Controller Overall Time Remaining': Sending state '6s'
[21:24:01][D][sensor:109]: 'Sprinkler Controller Overall Progress Percentage': Sending state 90.00000 with 1 decimals of accuracy
[21:24:02][D][text_sensor:064]: 'Sprinkler Zone 1 Time Remaining': Sending state '5s'
[21:24:02][D][sensor:109]: 'Sprinkler Zone 1 Progress Percentage': Sending state 83.00000 with 1 decimals of accuracy
[21:24:02][D][text_sensor:064]: 'Sprinkler Controller Overall Time Remaining': Sending state '5s'
[21:24:02][D][sensor:109]: 'Sprinkler Controller Overall Progress Percentage': Sending state 91.00000 with 1 decimals of accuracy
[21:24:03][D][text_sensor:064]: 'Sprinkler Zone 1 Time Remaining': Sending state '4s'
[21:24:03][D][sensor:109]: 'Sprinkler Zone 1 Progress Percentage': Sending state 86.00000 with 1 decimals of accuracy
[21:24:03][D][text_sensor:064]: 'Sprinkler Controller Overall Time Remaining': Sending state '4s'
[21:24:03][D][sensor:109]: 'Sprinkler Controller Overall Progress Percentage': Sending state 93.00000 with 1 decimals of accuracy
[21:24:04][D][text_sensor:064]: 'Sprinkler Zone 1 Time Remaining': Sending state '3s'
[21:24:04][D][sensor:109]: 'Sprinkler Zone 1 Progress Percentage': Sending state 90.00000 with 1 decimals of accuracy
[21:24:04][D][text_sensor:064]: 'Sprinkler Controller Overall Time Remaining': Sending state '3s'
[21:24:04][D][sensor:109]: 'Sprinkler Controller Overall Progress Percentage': Sending state 95.00000 with 1 decimals of accuracy
[21:24:05][D][text_sensor:064]: 'Sprinkler Zone 1 Time Remaining': Sending state '2s'
[21:24:05][D][sensor:109]: 'Sprinkler Zone 1 Progress Percentage': Sending state 93.00000 with 1 decimals of accuracy
[21:24:05][D][text_sensor:064]: 'Sprinkler Controller Overall Time Remaining': Sending state '2s'
[21:24:05][D][sensor:109]: 'Sprinkler Controller Overall Progress Percentage': Sending state 96.00000 with 1 decimals of accuracy
[21:24:06][D][text_sensor:064]: 'Sprinkler Zone 1 Time Remaining': Sending state '1s'
[21:24:06][D][sensor:109]: 'Sprinkler Zone 1 Progress Percentage': Sending state 96.00000 with 1 decimals of accuracy
[21:24:06][D][text_sensor:064]: 'Sprinkler Controller Overall Time Remaining': Sending state '1s'
[21:24:06][D][sensor:109]: 'Sprinkler Controller Overall Progress Percentage': Sending state 98.00000 with 1 decimals of accuracy
[21:24:06][D][sensor:109]: 'WiFi Signal': Sending state -67.00000 dBm with 0 decimals of accuracy
[21:24:07][D][text_sensor:064]: 'Sprinkler Zone 1 Time Remaining': Sending state '0s'
[21:24:07][D][sensor:109]: 'Sprinkler Zone 1 Progress Percentage': Sending state 100.00000 with 1 decimals of accuracy
[21:24:07][D][text_sensor:064]: 'Sprinkler Controller Overall Time Remaining': Sending state '0s'
[21:24:07][D][sensor:109]: 'Sprinkler Controller Overall Progress Percentage': Sending state 100.00000 with 1 decimals of accuracy
[21:24:07][D][switch:016]: 'Relay 1' Turning OFF.
[21:24:07][D][switch:055]: 'Relay 1': Sending state OFF
[21:24:07][D][switch:055]: 'Sprinkler Zone 1': Sending state OFF
[21:24:07][D][text_sensor:064]: 'Sprinkler Controller Status': Sending state 'Idle'
[21:24:07][D][text_sensor:064]: 'Sprinkler Zone 1 Status': Sending state 'Idle'
[21:24:07][D][text_sensor:064]: 'Sprinkler Zone 1 Time Remaining': Sending state '--'
[21:24:17][D][sprinkler:1364]: CYCLE is starting valve 1 for 30 seconds, cycle 1 of 1
[21:24:17][D][switch:012]: 'Relay 2' Turning ON.
[21:24:17][D][switch:055]: 'Relay 2': Sending state ON
[21:24:17][D][switch:055]: 'Sprinkler Zone 2': Sending state ON
[21:24:17][D][text_sensor:064]: 'Sprinkler Controller Status': Sending state 'Zone 2 Active'
[21:24:17][D][text_sensor:064]: 'Sprinkler Zone 2 Status': Sending state 'Running'
[21:24:17][D][text_sensor:064]: 'Sprinkler Zone 2 Time Remaining': Sending state '29s'
[21:24:17][D][sensor:109]: 'Sprinkler Zone 2 Progress Percentage': Sending state 3.00000 with 1 decimals of accuracy
[21:24:18][D][sensor:109]: 'Sprinkler Controller Status Internal': Sending state 2.00000 with 1 decimals of accuracy
[21:24:18][D][text_sensor:064]: 'Sprinkler Controller Overall Time Remaining': Sending state '29s'
Always happy to help. 😄 Don't mean to push back much -- I actually use and run into this myself, hence why I was like, "yup." 😆 Unfortunately yes, it did get written off as "too much code for too little gain" which I will absolutely apologize for. 😇 Regardless, good catch and please let me/us know if you run into any other issues. Before all too terribly long, we'll iterate again to bring about even more fancy things... 😉
Can
time_remaining_current_operation()
also somewhat defective due to the same reason when valve open delay is being used?
It's possible but I don't think so...but maybe. I don't recall this being an issue but I'll take a closer look.
I didn't feel any offense at all for what you would need to apologize for. I really know what does that mean, especially a case when you need to write code for something you don't use, don't feel the need or don't see the added value. Luckily - for me - in this case you seems to be at least a tiny bit impacted... :).
Re time_remaining_current_operation()
: unfortunately it seems to be impacted by this issue as well as total_cycle_time_enabled_incomplete_valves()
. The outputs from both methods are getting out of order as soon as the "marking complete" point is reached. They are working perfectly fine without valve open delay.
Re other issues, please let me know where/ how to communicate them the most efficiently. I ran into a couple of smaller ones what needed some workarounds. Shall I open a ticket one-by-one on all those here?
Can you briefly summarize what other issues you are running into? ...From there we can decide if it warrants opening another issue on GH or if it's a simple "just do this" type of thing. No need to paste lengthy code snips for demonstrating the issue, just a one-line or so summary is fine. I'm just curious what else you are running into.
Rather small stuff, nothing very crucial:
I appreciate 4 and 5 might be possible, it is just that I am lacking the skills using them?!
Cool -- I can respond to those things. 😄
controller_state()
simply returns the state of the controller's internal state machine; "paused" is not a state handled by this mechanism so it won't be reflected this way. If you want to know if the controller is paused, take a look at this section in the documentation -- specifically, the paused_valve()
method can reveal this._
) is a protected method; it's for internal use by the object. You can't access these methods from outside of the class. It probably would make sense to expose the next/previous valve methods, but state_as_str_()
is there for debugging purposes only (it's not useful to those who don't want or don't speak English). I'm also weary about exposing much of the state machine as I don't want people building a bunch of dependencies on that functionality. Future updates might bring about a different implementation for scheduling which behaves differently and then we end up with a lot of unhappy people. 😇Many thanks for the quick feedback!
May I have some additional inputs/ comments on them:
sprinkler.start_full_cycle
on the drip_ctrl
. As soon as I add a second dummy/ unused valve with main_switch
, auto_advance_switch
and an enable_switch
, the multiplier_number immediately gets exposed and the API service and the controller start functioning as expected.sprinkler:
- id: drip_ctrl
multiplier_number:
name: Drip Multiplier
mode: BOX
icon: mdi:timer-cog-outline
initial_value: 1.0
min_value: 0.0
max_value: 6.0
step: 0.1
restore_value: true
entity_category: config
valves:
- valve_switch:
name: Drip Zone
valve_switch_id: relay3
run_duration_number:
name: Drip Zone 1 Duration
unit_of_measurement: min
mode: BOX
icon: mdi:timer-outline
initial_value: 30
min_value: 0
max_value: 120
step: 1
restore_value: true
entity_category: config
OK, I just added this, because you were asking where I needed workarounds. Besides the paused state, I am also missing a pending state here (when the controller is waiting for example during valve open times). In my workaround, I added a fuzzy logic (what I don't find super-robust) to publish states between switches and sensors back and forth to achieve to have a full comprehensive controller status sensor.
Thank you very much in advance!
and 5. OK, clear, thank you for the explanation.
Then I forgot to mention two non-sprinkler related feature one for ESPHome and one for HA what I am badly missing and would be super-useful to have in a sprinkler config environment. Not sure if I should mention these here, but let me try, while I am having your attention:
Hi I'm jumping on this issue as I've just started using this integration - it's fantastic so far!
I have noticed that the function .total_queue_time()
doesn't seem to give the correct time, it seems to miss the first valve in the queue, whereas .time_remaining_current_operation().value()
gives the correct time.
- A text sensor filter for text template sensors to store the last value passed through this filter and only passes incoming values through if incoming value is different from the previously passed one (similarly to delta sensor for numeric sensors, but for text/ strings). Using this one could avoid to publish text sensor state on each "update_interval" - would be very handy for example for configuring text template sensors for human readable formatted remaining time.
I also wanted to avoid having repeated "Finished" or "0s" being continuously published when using update_interval
to publish the remaining time via a text sensor. The solution I found is to use a script, and put a while time_remaining_current_operation().has_value() == true
, like this:
script:
- id: publish_sprinkler_time
then:
- while:
condition:
lambda: 'return id(sprinkler_controller).time_remaining_current_operation().has_value();'
then:
- text_sensor.template.publish:
id: text_time_remaining
state: !lambda |-
return seconds_to_readable(id(sprinkler_controller).time_remaining_current_operation().value());
- delay: 5s
- text_sensor.template.publish:
id: text_time_remaining
state: "Finished"
and you call the script where you start your sprinkler queue or turn on the master switch or whatever, for me it's from another script where I create my sprinkler queue like so:
script:
#
# Program A - GARDENS
#
- id: watering_program_a
then:
- sprinkler.clear_queued_valves:
id: sprinkler_controller
- sprinkler.queue_valve:
id: sprinkler_controller
valve_number: 3 # Zone 4 BACK GARDEN
run_duration: 0s
- sprinkler.queue_valve:
id: sprinkler_controller
valve_number: 4 # Zone 5 POOL GARDEN
run_duration: 0s
- sprinkler.queue_valve:
id: sprinkler_controller
valve_number: 5 # Zone 6 FRONT GARDEN
run_duration: 0s
- sprinkler.start_from_queue:
id: sprinkler_controller
- script.execute: publish_queue_time
- script.execute: publish_sprinkler_time
@kbx81 Keith please note, those last two lines give me different results as per my previous post where the queue time looks like this:
- id: publish_queue_time
then:
- text_sensor.template.publish:
id: text_total_queue_time
state: !lambda |-
return seconds_to_readable(id(sprinkler_controller).total_queue_time());
Also the documentation says the run_duration default will be whatever is set for the valve, except the yaml validation fails if I delete those lines with run_duration: 0s
.
Many thanks for the quick feedback!
May I have some additional inputs/ comments on them:
- I am not actually missing the main switch, but I thought (probably incorrectly) that the cycle functions are only working if the main switch exists. The main issue here is that using the below config for a single valve drip controller I don't even get the multiplier_number exposed to HA
Hmm, this is interesting -- I'll look into it. That definitely doesn't make any sense, as you should still be able to use the multiplier in this case. 😇
I am also unable to start the drip controller, by using the API service I configured to
sprinkler.start_full_cycle
on thedrip_ctrl
. As soon as I add a second dummy/ unused valve withmain_switch
,auto_advance_switch
and anenable_switch
, the multiplier_number immediately gets exposed and the API service and the controller start functioning as expected.
I'm curious about your motivation for using sprinkler.start_full_cycle
with a single valve. Wouldn't you just refer directly to the single valve and use sprinkler.start_single_valve
, instead? There should be no behavioral difference, although I do agree that sprinkler.start_full_cycle
should still work in this scenario -- another thing I'll look into. 😉
- OK, I just added this, because you were asking where I needed workarounds. Besides the paused state, I am also missing a pending state here (when the controller is waiting for example during valve open times). In my workaround, I added a fuzzy logic (what I don't find super-robust) to publish states between switches and sensors back and forth to achieve to have a full comprehensive controller status sensor.
The controller's state machines only track/use the states you see here. If you want more specific detail, you need to code that up yourself. The state machine is intended to support the core functionality of the controller, not enumerate every possible state anyone anywhere might be interested in. 😇
Personal opinion/side note: I'm really not interested in creating states for every possible controller mode/behavior. For example, do you consider "paused" with auto-advance enabled a different state than "paused" when auto-advance is disabled? This is a gray area I really do not want to get into, so (imho) what states the state machine tracks & reports should remain limited to the bare essentials it needs to operate. If you are interested in tracking other states/behavior, there are already mechanisms available to allow you to do so.
- Thank you very much in advance!
- and 5. OK, clear, thank you for the explanation.
You're welcome -- hope this helps! 🍻
Then I forgot to mention two non-sprinkler related feature one for ESPHome and one for HA what I am badly missing and would be super-useful to have in a sprinkler config environment. Not sure if I should mention these here, but let me try, while I am having your attention:
- A text sensor filter for text template sensors to store the last value passed through this filter and only passes incoming values through if incoming value is different from the previously passed one (similarly to delta sensor for numeric sensors, but for text/ strings). Using this one could avoid to publish text sensor state on each "update_interval" - would be very handy for example for configuring text template sensors for human readable formatted remaining time.
- It would be nice to have an option in HA to set the format of time displayed for sensors with duration device_class. Currently this is displayed with DD:HH:MM:SS and would be great to see them more human readable, i.e. like 1d 1h 23m 47s. This way, it would be even more easier to have the time remaining display in a nice way. Looking at the HA forums, most users prefer this for sprinklers opposed to DD:HH:MM:SS.
For these, you should ask on Discord and/or open new feature requests -- but be sure to carefully check the docs so you're not being redundant! 😉
time_remaining_current_operation()
and total_cycle_time_enabled_incomplete_valves()
seem to report incorrect times when valve open delay is usedtotal_queue_time()
seems to miss the first valve in the queue -- UPDATE: expected behaviorsprinkler.start_full_cycle
does not seem to work with a single valve controllermultiplier_number
component doesn't appear in front end when used with a single valve controllerrun_duration
is not optional in sprinkler.queue_valve
(but should be) -- UPDATES: see https://github.com/esphome/issues/issues/4069 -- fixed in https://github.com/esphome/esphome/pull/4806Let me know if I've missed anything in this list! 😇
Hi I'm jumping on this issue as I've just started using this integration - it's fantastic so far!
I have noticed that the function
.total_queue_time()
doesn't seem to give the correct time, it seems to miss the first valve in the queue, whereas.time_remaining_current_operation().value()
gives the correct time.
@patfelst could you clarify what you mean by "miss the first valve in the queue"? I was just taking a quick peek at the code that does this here and I don't really see how that's possible.
Did you mean that it's not including the valve that is currently running? If so, that's by design -- the valve that's running is no longer considered to be in the queue because it is the active valve. If you want the correct time, you need to add the result from total_queue_time()
and time_remaining_active_valve()
to get this. 😇 Perhaps this is something that could be clarified in the docs/comments.
yes that's what I meant, well I'm reporting total_queue_time()
just after I start it, and I was expecting to see a few seconds under the queue time of adding up the valve times. But what you say makes sense, I'll try your solution.
Actually isn't this redundant, because via testing I've noticed that I get the expected remaining time via reporting time_remaining_current_operation().value()
? I guess in the situation where you create a queue, but not start it, you might want to know that time.
yes that's what I meant, well I'm reporting
total_queue_time()
just after I start it, and I was expecting to see a few seconds under the queue time of adding up the valve times. But what you say makes sense, I'll try your solution.
Sweet! I think that will get you the behavior you're looking for. 😄
Actually isn't this redundant, because via testing I've noticed that I get the expected remaining time via reporting
time_remaining_current_operation().value()
? I guess in the situation where you create a queue, but not start it, you might want to know that time.
Yes, I broke the functionality out for different things in different ways because everybody seems to want to know something different. 😆 I believe that with the methods available, at this point, you should be able to get any combination of things, with a couple super-common-everybody-wants-this methods built-in. In other words, if you want something other than time remaining current valve or time remaining all inclusive, you should be able to pull that together using some combination of the methods already there. 😇
Regarding the text sensors, have you tried just using a regular sensor
and setting device_class: duration
to get "pretty" formatting in the front end? Seems a lot simpler than all of the extra code to make the text sensor work just so. 😇
Hey @kbx81 thanks for your responses, very helpful. I think your comment about pretty formatting is for @olympia but I'm interested too. From a quick search it seems formatting durations on the HA side front end is maybe not so easy, e.g. https://community.home-assistant.io/t/understanding-device-class-duration-better/444140. Maybe there are simpler solutions I'm not aware of, but looks like some templating would need to be done, and I think it simpler in C++ personally :laughing:
This is how I approached it to make the yaml code a bit more readable, I created this function in a .h
include file:
/*
** convert a number of seconds to a human readable C++ string in the format:
** "dd hh mm ss"
*/
std::string seconds_to_readable(int sec) {
int seconds = sec;
int minutes = 0;
int hours = 0;
int days = 0;
std::string txt = "";
days = seconds / (24 * 3600);
seconds = seconds % (24 * 3600);
hours = seconds / 3600;
seconds = seconds % 3600;
minutes = seconds / 60;
seconds = seconds % 60;
if (days) txt = (to_string(days) + "d "); else "";
if (hours) txt+= (to_string(hours) + "h "); else "";
if (minutes) txt+= (to_string(minutes) + "m "); else "";
txt+= to_string(seconds) + "s";
// ESP_LOGW("Sprinkler debug", "Time remaining is %s", txt.c_str());
return txt;
}
then you can publish the text sensor like:
- text_sensor.template.publish:
id: text_time_remaining
state: !lambda |-
return seconds_to_readable(id(sprinkler_controller).time_remaining_current_operation().value());
and you can add to the text if you need, like I added the current queue name (I call it a program aka Rainbird irrigation naming)
...
- lambda: 'id(current_program_str) = "Prog A";'
...
- text_sensor.template.publish:
id: text_total_queue_time
state: !lambda |-
std::string prog_txt = "";
prog_txt = id(current_program_str) + " " +
seconds_to_readable(id(sprinkler_controller).total_queue_time());
return prog_txt;
Regarding the text sensors, have you tried just using a regular
sensor
and settingdevice_class: duration
to get "pretty" formatting in the front end? Seems a lot simpler than all of the extra code to make the text sensor work just so. 😇
That's the approach I mentioned above what I tried and was wondering about a formatting feature in HA for. The cosmetic issue with this is that the way HA displays device_class: duration
is still not pretty/ human readable enough. HA will display such sensors as 10:10:10 while the bulky code we sprinkler funs are usually adding (quoted by Patrick) are making it much more human readable: 10h 10m 10s. Hence I was wondering about an option to get this configurable in HA frontend, but I fully get and appreciate this is out of scope here.
Issue Summary
time_remaining_current_operation()
andtotal_cycle_time_enabled_incomplete_valves()
seem to report incorrect times when valve open delay is usedtotal_queue_time()
seems to miss the first valve in the queue -- UPDATE: expected behaviorsprinkler.start_full_cycle
does not seem to work with a single valve controllermultiplier_number
component doesn't appear in front end when used with a single valve controllerrun_duration
is not optional insprinkler.queue_valve
(but should be) -- UPDATE: see sprinkler.queue_valve fails without run_duration #4069Let me know if I've missed anything in this list! 😇
Thanks for the summary:
May I ask the followings to be added too:
Please test https://github.com/esphome/esphome/pull/4816 and let me know if this helps. You can test it using external components like this:
external_components:
- source: github://pr#4816
components: [ sprinkler ]
Please test esphome/esphome#4816 and let me know if this helps. You can test it using external components like this:
external_components: - source: github://pr#4816 components: [ sprinkler ]
Wow, didn't expect such quick turn around time, many thanks @kbx81!
Just tested, here are the results:
sprinkler.start_full_cycle
does not seem to work with a single valve controller -- FIXED, thanks!multiplier_number
component doesn't appear in front end when used with a single valve controller -- FIXED, thanks!total_cycle_time_all_valves()
didn't calculate with the open valve delay time -- FIXED, thanks!active_valve()
seem to report incorrect valve when valve open delay is used (during the opening delay) -- I am still a bit somewhat confused here, so I might came back re this, nevertheless this also seems to be FIXED, thanks. Can you confirm that while this is correct, the marker point in the log is still on the wrong place?total_cycle_time_enabled_incomplete_valves()
seem to report incorrect times when valve open delay is used -- this still doesn't seems to report the correct value. Interesting is that the value seems to be correct after a clean boot and summing up Valve 1 + Valve 2 + valve open delay time, but gets incorrect once a cycle is initiated, then it will only calculate with Valve 2 without the valve open delay time -- does this make sense?time_remaining_current_operation()
seem to report incorrect times when valve open delay is used -- this still seems to report incorrect time remaining. I still see two issues here: 1) not counting with the valve open delay time and 2) this actually reports 0 during valve open delayWow, didn't expect such quick turn around time, many thanks @kbx81!
The first couple points were "stupid" issues that shouldn't have been an issue in the first place -- easy fixes. 😇
sprinkler.start_full_cycle
does not seem to work with a single valve controller -- FIXED, thanks!multiplier_number
component doesn't appear in front end when used with a single valve controller -- FIXED, thanks!total_cycle_time_all_valves()
didn't calculate with the open valve delay time -- FIXED, thanks!
Awesome, glad to hear it and thanks for confirming! 🍻
active_valve()
seem to report incorrect valve when valve open delay is used (during the opening delay) -- I am still a bit somewhat confused here, so I might came back re this, nevertheless this also seems to be FIXED, thanks. Can you confirm that while this is correct, the marker point in the log is still on the wrong place?
Cool, glad this seems to be producing behavior that's a bit more in-line with what's expected. As for the logs, honestly, don't worry about that; what you're seeing in the logs is messaging generated by the state machine transitioning states/control. The behavior of the state machine is somewhat different from what we as humans might expect, but it is what's generating the messages in the logs. Regardless of these messages/behaviors, the valves will still perform as expected.
total_cycle_time_enabled_incomplete_valves()
seem to report incorrect times when valve open delay is used -- this still doesn't seems to report the correct value. Interesting is that the value seems to be correct after a clean boot and summing up Valve 1 + Valve 2 + valve open delay time, but gets incorrect once a cycle is initiated, then it will only calculate with Valve 2 without the valve open delay time -- does this make sense?
Yeah, I was hoping that the tweaking I did to active_valve()
would fix it, but apparently not. I just took another look and did some work to address it -- it's still not perfect but much closer I think. Please test again and let me know how it works. 😇
time_remaining_current_operation()
seem to report incorrect times when valve open delay is used -- this still seems to report incorrect time remaining. I still see two issues here: 1) not counting with the valve open delay time and 2) this actually reports 0 during valve open delay
As above -- this should be (mostly) addressed, too. You'll still see the timer "hang" during the valve open delay, but it will at least report a sane value now and just pick up once the valve actually starts. I forgot how complex this whole thing is; the reason for this behavior is because there is no visibility into the timers used in the set_timeout
functions we have in ESPHome. The sprinkler controller's timers will need to be re-worked to use a mechanism that's independent of this and that's a bit more work than I can take on right now. Hopefully this at least puts you into a better spot for the time being. 😄
In any event, please try with these latest changes and let me/us know if it's all behaving as expected now. 😇
time_remaining_current_operation()
seem to report incorrect times when valve open delay is used -- this still seems to report incorrect time remaining. I still see two issues here: 1) not counting with the valve open delay time and 2) this actually reports 0 during valve open delayAs above -- this should be (mostly) addressed, too. You'll still see the timer "hang" during the valve open delay, but it will at least report a sane value now and just pick up once the valve actually starts. I forgot how complex this whole thing is; the reason for this behavior is because there is no visibility into the timers used in the
set_timeout
functions we have in ESPHome. The sprinkler controller's timers will need to be re-worked to use a mechanism that's independent of this and that's a bit more work than I can take on right now. Hopefully this at least puts you into a better spot for the time being. 😄In any event, please try with these latest changes and let me/us know if it's all behaving as expected now. 😇
I suppose the timer "hanging" means that time_remaining_current_operation()
will not include the valve open delay, but it should stop counting down during valve open delay, right. I.e. If you have 2 valves, each with 1 min run duration and 10s open valve delay then time_remaining_current_operation()
should start counting down from 2 mins (not including the 10s open valve delay time), stop counting down at 1min during 10s valve open delay time when both valves are closed and then should start counting down again as soon as valve 2 started. Is this a correct interpretation?
If yes, then this is not what's happening. Please see Sprinkler Controller Overall Time Remaining
in the below log. It reports 0s when valve open delay is active.
(one question here though: should I add anything to the esphome code to enforce re-downloading of new commits from the external component - I didn't see any evidence in the compile logs that it redownloaded your latest changes).
Nevertheless, on top of that, if my above interpretation of what "hang" means is correct, then I suppose for the sake of consistency nor total_cycle_time_all_valves()
, neither total_cycle_time_enabled_incomplete_valves()
should have the valve open delay time added (opposed to what I was asking for initially).
This is because one should be able to calculate overall progress percentage using:
((id(sprinkler_ctrl).total_cycle_time_all_valves() - id(sprinkler_ctrl).time_remaining_current_operation().value_or(0)) * 100 / id(sprinkler_ctrl).total_cycle_time_all_valves() );
If time_remaining_current_operation()
doesn't have open valve delay time included, but total_cycle_time_all_valves()
does, then this math will return an incorrect percentage.
Logs:
[10:27:18][D][text_sensor:064]: 'Sprinkler Controller Overall Time Remaining': Sending state '1m 5s'
[10:27:18][D][sensor:109]: 'Sprinkler Controller Overall Progress Percentage': Sending state 50.00000 with 1 decimals of accuracy
[10:27:19][D][text_sensor:064]: 'Sprinkler Zone 1 Time Remaining': Sending state '4s'
[10:27:19][D][sensor:109]: 'Sprinkler Zone 1 Progress Percentage': Sending state 93.00000 with 1 decimals of accuracy
[10:27:19][D][text_sensor:064]: 'Sprinkler Controller Overall Time Remaining': Sending state '1m 4s'
[10:27:20][D][text_sensor:064]: 'Sprinkler Zone 1 Time Remaining': Sending state '3s'
[10:27:20][D][sensor:109]: 'Sprinkler Zone 1 Progress Percentage': Sending state 95.00000 with 1 decimals of accuracy
[10:27:20][D][text_sensor:064]: 'Sprinkler Controller Overall Time Remaining': Sending state '1m 3s'
[10:27:20][D][sensor:109]: 'Sprinkler Controller Overall Progress Percentage': Sending state 51.00000 with 1 decimals of accuracy
[10:27:21][D][text_sensor:064]: 'Sprinkler Zone 1 Time Remaining': Sending state '2s'
[10:27:21][D][sensor:109]: 'Sprinkler Zone 1 Progress Percentage': Sending state 96.00000 with 1 decimals of accuracy
[10:27:21][D][text_sensor:064]: 'Sprinkler Controller Overall Time Remaining': Sending state '1m 2s'
[10:27:21][D][sensor:109]: 'Sprinkler Controller Overall Progress Percentage': Sending state 52.00000 with 1 decimals of accuracy
[10:27:22][D][text_sensor:064]: 'Sprinkler Zone 1 Time Remaining': Sending state '1s'
[10:27:22][D][sensor:109]: 'Sprinkler Zone 1 Progress Percentage': Sending state 98.00000 with 1 decimals of accuracy
[10:27:22][D][text_sensor:064]: 'Sprinkler Controller Overall Time Remaining': Sending state '1m 1s'
[10:27:22][D][sensor:109]: 'Sprinkler Controller Overall Progress Percentage': Sending state 53.00000 with 1 decimals of accuracy
[10:27:23][D][text_sensor:064]: 'Sprinkler Zone 1 Time Remaining': Sending state '0s'
[10:27:23][D][sensor:109]: 'Sprinkler Zone 1 Progress Percentage': Sending state 100.00000 with 1 decimals of accuracy
[10:27:23][D][text_sensor:064]: 'Sprinkler Controller Overall Time Remaining': Sending state '1m 0s'
[10:27:24][D][switch:016]: 'Relay 1' Turning OFF.
[10:27:24][D][switch:055]: 'Relay 1': Sending state OFF
[10:27:24][D][switch:055]: 'Sprinkler Zone 1': Sending state OFF
[10:27:24][D][text_sensor:064]: 'Sprinkler Controller Status': Sending state 'Pending'
[10:27:24][D][text_sensor:064]: 'Sprinkler Zone 2 Status': Sending state 'Pending'
[10:27:24][D][text_sensor:064]: 'Sprinkler Zone 1 Status': Sending state 'Completed'
[10:27:24][D][text_sensor:064]: 'Sprinkler Controller Overall Time Remaining': Sending state '0s'
[10:27:24][D][sensor:109]: 'Sprinkler Controller Overall Progress Percentage': Sending state 100.00000 with 1 decimals of accuracy
[10:27:25][D][text_sensor:064]: 'Sprinkler Controller Overall Time Remaining': Sending state '0s'
[10:27:26][D][text_sensor:064]: 'Sprinkler Controller Overall Time Remaining': Sending state '0s'
[10:27:27][D][text_sensor:064]: 'Sprinkler Controller Overall Time Remaining': Sending state '0s'
[10:27:28][D][text_sensor:064]: 'Sprinkler Controller Overall Time Remaining': Sending state '0s'
[10:27:29][D][text_sensor:064]: 'Sprinkler Controller Overall Time Remaining': Sending state '0s'
[10:27:30][D][text_sensor:064]: 'Sprinkler Controller Overall Time Remaining': Sending state '0s'
[10:27:31][D][text_sensor:064]: 'Sprinkler Controller Overall Time Remaining': Sending state '0s'
[10:27:32][D][text_sensor:064]: 'Sprinkler Controller Overall Time Remaining': Sending state '0s'
[10:27:33][D][text_sensor:064]: 'Sprinkler Controller Overall Time Remaining': Sending state '0s'
[10:27:34][D][sprinkler:1379]: CYCLE is starting valve 1 for 60 seconds, cycle 1 of 1
[10:27:34][D][switch:012]: 'Relay 2' Turning ON.
[10:27:34][D][switch:055]: 'Relay 2': Sending state ON
[10:27:34][D][switch:055]: 'Sprinkler Zone 2': Sending state ON
[10:27:34][D][text_sensor:064]: 'Sprinkler Controller Status': Sending state 'Zone 2 Active'
[10:27:34][D][text_sensor:064]: 'Sprinkler Zone 2 Status': Sending state 'Running'
[10:27:34][D][text_sensor:064]: 'Sprinkler Controller Overall Time Remaining': Sending state '59s'
[10:27:34][D][sensor:109]: 'Sprinkler Controller Overall Progress Percentage': Sending state 54.00000 with 1 decimals of accuracy
[10:27:34][D][text_sensor:064]: 'Sprinkler Zone 2 Time Remaining': Sending state '59s'
[10:27:34][D][sensor:109]: 'Sprinkler Zone 2 Progress Percentage': Sending state 1.00000 with 1 decimals of accuracy
[10:27:35][D][text_sensor:064]: 'Sprinkler Controller Overall Time Remaining': Sending state '58s'
[10:27:35][D][sensor:109]: 'Sprinkler Controller Overall Progress Percentage': Sending state 55.00000 with 1 decimals of accuracy
[10:27:35][D][text_sensor:064]: 'Sprinkler Zone 2 Time Remaining': Sending state '58s'
[10:27:35][D][sensor:109]: 'Sprinkler Zone 2 Progress Percentage': Sending state 3.00000 with 1 decimals of accuracy
[10:27:36][D][text_sensor:064]: 'Sprinkler Controller Overall Time Remaining': Sending state '57s'
[10:27:36][D][sensor:109]: 'Sprinkler Controller Overall Progress Percentage': Sending state 56.00000 with 1 decimals of accuracy
[10:27:36][D][text_sensor:064]: 'Sprinkler Zone 2 Time Remaining': Sending state '57s'
[10:27:36][D][sensor:109]: 'Sprinkler Zone 2 Progress Percentage': Sending state 5.00000 with 1 decimals of accuracy
[10:27:37][D][text_sensor:064]: 'Sprinkler Controller Overall Time Remaining': Sending state '56s'
[10:27:37][D][text_sensor:064]: 'Sprinkler Zone 2 Time Remaining': Sending state '56s'
[10:27:37][D][sensor:109]: 'Sprinkler Zone 2 Progress Percentage': Sending state 6.00000 with 1 decimals of accuracy
[10:27:38][D][text_sensor:064]: 'Sprinkler Controller Overall Time Remaining': Sending state '55s'
[10:27:38][D][sensor:109]: 'Sprinkler Controller Overall Progress Percentage': Sending state 57.00000 with 1 decimals of accuracy
[10:27:38][D][text_sensor:064]: 'Sprinkler Zone 2 Time Remaining': Sending state '55s'
[10:27:38][D][sensor:109]: 'Sprinkler Zone 2 Progress Percentage': Sending state 8.00000 with 1 decimals of accuracy
[10:27:39][D][text_sensor:064]: 'Sprinkler Controller Overall Time Remaining': Sending state '54s'
I think something didn't refresh on your end. time_remaining_current_operation()
no longer returns zero during the valve open delay interval -- it should simply "pause"/stop counting during this interval, and "jump" down to match the correct time remaining when the valve actually starts. Try cleaning your build cache and re-run your build.
Yeah, that was kind of suspicious to me as well, hence my question in bold and of course you were right, cleaning the build cache was the cure.
...and I happily report that your latest changes indeed working on the way you described and with those few mentioned minor conditions, all functions we were discussing here are now having a very nice, almost perfect behavior!
Thank you very much for your attention and constructive and very fast fixes!
Are you going to merge this PR to the next ESPHome version?
Awesome -- happy to hear it and (again) thanks for re-testing and confirming!
Yes, I think we'll aim to get this into the 5.1 release this month. A comment on the PR to confirm you have acceptable behavior would also be great, if you don't mind. 😇
Sure thing Keith, done.
The problem
It looks like Sprinkler Controller is marking a valve completed too early if valve open delay is set.
In the attached log file it is visible that both "Marking valve 0 complete" and "Marking valve 1 complete" are kicking in 10s earlier (10s is the valve open delay what has been set) than the actual end time of the zone ('Relay 1' Turning OFF. and 'Relay 2' Turning OFF. respectively).
@kbx81 Is this something you could have a look?
Which version of ESPHome has the issue?
2023.4.4
What type of installation are you using?
Docker
Which version of Home Assistant has the issue?
2023.05
What platform are you using?
ESP8266
Board
sonoff 4ch pro
Component causing the issue
Sprinkler
Example YAML snippet
No response
Anything in the logs that might be useful for us?
Additional information
No response