mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 22:53:59 +00:00 
			
		
		
		
	Sprinkler controller component (#2249)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
		| @@ -193,6 +193,7 @@ esphome/components/smt100/* @piechade | |||||||
| esphome/components/socket/* @esphome/core | esphome/components/socket/* @esphome/core | ||||||
| esphome/components/sonoff_d1/* @anatoly-savchenkov | esphome/components/sonoff_d1/* @anatoly-savchenkov | ||||||
| esphome/components/spi/* @esphome/core | esphome/components/spi/* @esphome/core | ||||||
|  | esphome/components/sprinkler/* @kbx81 | ||||||
| esphome/components/sps30/* @martgras | esphome/components/sps30/* @martgras | ||||||
| esphome/components/ssd1322_base/* @kbx81 | esphome/components/ssd1322_base/* @kbx81 | ||||||
| esphome/components/ssd1322_spi/* @kbx81 | esphome/components/ssd1322_spi/* @kbx81 | ||||||
|   | |||||||
							
								
								
									
										599
									
								
								esphome/components/sprinkler/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										599
									
								
								esphome/components/sprinkler/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,599 @@ | |||||||
|  | import esphome.codegen as cg | ||||||
|  | import esphome.config_validation as cv | ||||||
|  | from esphome import automation | ||||||
|  | from esphome.automation import maybe_simple_id | ||||||
|  | from esphome.components import switch | ||||||
|  | from esphome.const import ( | ||||||
|  |     CONF_ID, | ||||||
|  |     CONF_NAME, | ||||||
|  |     CONF_REPEAT, | ||||||
|  |     CONF_RUN_DURATION, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | AUTO_LOAD = ["switch"] | ||||||
|  | CODEOWNERS = ["@kbx81"] | ||||||
|  |  | ||||||
|  | CONF_AUTO_ADVANCE_SWITCH = "auto_advance_switch" | ||||||
|  | CONF_ENABLE_SWITCH = "enable_switch" | ||||||
|  | CONF_MAIN_SWITCH = "main_switch" | ||||||
|  | CONF_MANUAL_SELECTION_DELAY = "manual_selection_delay" | ||||||
|  | CONF_MULTIPLIER = "multiplier" | ||||||
|  | CONF_PUMP_OFF_SWITCH_ID = "pump_off_switch_id" | ||||||
|  | CONF_PUMP_ON_SWITCH_ID = "pump_on_switch_id" | ||||||
|  | CONF_PUMP_PULSE_DURATION = "pump_pulse_duration" | ||||||
|  | CONF_PUMP_START_PUMP_DELAY = "pump_start_pump_delay" | ||||||
|  | CONF_PUMP_START_VALVE_DELAY = "pump_start_valve_delay" | ||||||
|  | CONF_PUMP_STOP_PUMP_DELAY = "pump_stop_pump_delay" | ||||||
|  | CONF_PUMP_STOP_VALVE_DELAY = "pump_stop_valve_delay" | ||||||
|  | CONF_PUMP_SWITCH = "pump_switch" | ||||||
|  | CONF_PUMP_SWITCH_ID = "pump_switch_id" | ||||||
|  | CONF_PUMP_SWITCH_OFF_DURING_VALVE_OPEN_DELAY = "pump_switch_off_during_valve_open_delay" | ||||||
|  | CONF_QUEUE_ENABLE_SWITCH = "queue_enable_switch" | ||||||
|  | CONF_REVERSE_SWITCH = "reverse_switch" | ||||||
|  | CONF_VALVE_NUMBER = "valve_number" | ||||||
|  | CONF_VALVE_OPEN_DELAY = "valve_open_delay" | ||||||
|  | CONF_VALVE_OVERLAP = "valve_overlap" | ||||||
|  | CONF_VALVE_PULSE_DURATION = "valve_pulse_duration" | ||||||
|  | CONF_VALVE_OFF_SWITCH_ID = "valve_off_switch_id" | ||||||
|  | CONF_VALVE_ON_SWITCH_ID = "valve_on_switch_id" | ||||||
|  | CONF_VALVE_SWITCH = "valve_switch" | ||||||
|  | CONF_VALVE_SWITCH_ID = "valve_switch_id" | ||||||
|  | CONF_VALVES = "valves" | ||||||
|  |  | ||||||
|  | sprinkler_ns = cg.esphome_ns.namespace("sprinkler") | ||||||
|  | Sprinkler = sprinkler_ns.class_("Sprinkler", cg.Component) | ||||||
|  | SprinklerControllerSwitch = sprinkler_ns.class_( | ||||||
|  |     "SprinklerControllerSwitch", switch.Switch, cg.Component | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | SetMultiplierAction = sprinkler_ns.class_("SetMultiplierAction", automation.Action) | ||||||
|  | QueueValveAction = sprinkler_ns.class_("QueueValveAction", automation.Action) | ||||||
|  | ClearQueuedValvesAction = sprinkler_ns.class_( | ||||||
|  |     "ClearQueuedValvesAction", automation.Action | ||||||
|  | ) | ||||||
|  | SetRepeatAction = sprinkler_ns.class_("SetRepeatAction", automation.Action) | ||||||
|  | SetRunDurationAction = sprinkler_ns.class_("SetRunDurationAction", automation.Action) | ||||||
|  | StartFromQueueAction = sprinkler_ns.class_("StartFromQueueAction", automation.Action) | ||||||
|  | StartFullCycleAction = sprinkler_ns.class_("StartFullCycleAction", automation.Action) | ||||||
|  | StartSingleValveAction = sprinkler_ns.class_( | ||||||
|  |     "StartSingleValveAction", automation.Action | ||||||
|  | ) | ||||||
|  | ShutdownAction = sprinkler_ns.class_("ShutdownAction", automation.Action) | ||||||
|  | NextValveAction = sprinkler_ns.class_("NextValveAction", automation.Action) | ||||||
|  | PreviousValveAction = sprinkler_ns.class_("PreviousValveAction", automation.Action) | ||||||
|  | PauseAction = sprinkler_ns.class_("PauseAction", automation.Action) | ||||||
|  | ResumeAction = sprinkler_ns.class_("ResumeAction", automation.Action) | ||||||
|  | ResumeOrStartAction = sprinkler_ns.class_("ResumeOrStartAction", automation.Action) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def validate_sprinkler(config): | ||||||
|  |     for sprinkler_controller_index, sprinkler_controller in enumerate(config): | ||||||
|  |         if len(sprinkler_controller[CONF_VALVES]) <= 1: | ||||||
|  |             exclusions = [ | ||||||
|  |                 CONF_VALVE_OPEN_DELAY, | ||||||
|  |                 CONF_VALVE_OVERLAP, | ||||||
|  |                 CONF_AUTO_ADVANCE_SWITCH, | ||||||
|  |                 CONF_MAIN_SWITCH, | ||||||
|  |                 CONF_REVERSE_SWITCH, | ||||||
|  |             ] | ||||||
|  |             for config_item in exclusions: | ||||||
|  |                 if config_item in sprinkler_controller: | ||||||
|  |                     raise cv.Invalid(f"Do not define {config_item} with only one valve") | ||||||
|  |             if CONF_ENABLE_SWITCH in sprinkler_controller[CONF_VALVES][0]: | ||||||
|  |                 raise cv.Invalid( | ||||||
|  |                     f"Do not define {CONF_ENABLE_SWITCH} with only one valve" | ||||||
|  |                 ) | ||||||
|  |         else: | ||||||
|  |             requirements = [ | ||||||
|  |                 CONF_AUTO_ADVANCE_SWITCH, | ||||||
|  |                 CONF_MAIN_SWITCH, | ||||||
|  |             ] | ||||||
|  |             for config_item in requirements: | ||||||
|  |                 if config_item not in sprinkler_controller: | ||||||
|  |                     raise cv.Invalid( | ||||||
|  |                         f"{config_item} is a required option for {sprinkler_controller_index}" | ||||||
|  |                     ) | ||||||
|  |  | ||||||
|  |         if ( | ||||||
|  |             CONF_PUMP_SWITCH_OFF_DURING_VALVE_OPEN_DELAY in sprinkler_controller | ||||||
|  |             and CONF_VALVE_OPEN_DELAY not in sprinkler_controller | ||||||
|  |         ): | ||||||
|  |             if sprinkler_controller[CONF_PUMP_SWITCH_OFF_DURING_VALVE_OPEN_DELAY]: | ||||||
|  |                 raise cv.Invalid( | ||||||
|  |                     f"{CONF_VALVE_OPEN_DELAY} must be defined when {CONF_PUMP_SWITCH_OFF_DURING_VALVE_OPEN_DELAY} is enabled" | ||||||
|  |                 ) | ||||||
|  |  | ||||||
|  |         for valve in sprinkler_controller[CONF_VALVES]: | ||||||
|  |             if ( | ||||||
|  |                 CONF_VALVE_OVERLAP in sprinkler_controller | ||||||
|  |                 and valve[CONF_RUN_DURATION] <= sprinkler_controller[CONF_VALVE_OVERLAP] | ||||||
|  |             ): | ||||||
|  |                 raise cv.Invalid( | ||||||
|  |                     f"{CONF_RUN_DURATION} must be greater than {CONF_VALVE_OVERLAP}" | ||||||
|  |                 ) | ||||||
|  |             if ( | ||||||
|  |                 CONF_VALVE_OPEN_DELAY in sprinkler_controller | ||||||
|  |                 and valve[CONF_RUN_DURATION] | ||||||
|  |                 <= sprinkler_controller[CONF_VALVE_OPEN_DELAY] | ||||||
|  |             ): | ||||||
|  |                 raise cv.Invalid( | ||||||
|  |                     f"{CONF_RUN_DURATION} must be greater than {CONF_VALVE_OPEN_DELAY}" | ||||||
|  |                 ) | ||||||
|  |             if ( | ||||||
|  |                 CONF_PUMP_OFF_SWITCH_ID in valve and CONF_PUMP_ON_SWITCH_ID not in valve | ||||||
|  |             ) or ( | ||||||
|  |                 CONF_PUMP_ON_SWITCH_ID in valve and CONF_PUMP_OFF_SWITCH_ID not in valve | ||||||
|  |             ): | ||||||
|  |                 raise cv.Invalid( | ||||||
|  |                     f"Both {CONF_PUMP_OFF_SWITCH_ID} and {CONF_PUMP_ON_SWITCH_ID} must be specified for latching pump configuration" | ||||||
|  |                 ) | ||||||
|  |             if CONF_PUMP_SWITCH_ID in valve and ( | ||||||
|  |                 CONF_PUMP_OFF_SWITCH_ID in valve or CONF_PUMP_ON_SWITCH_ID in valve | ||||||
|  |             ): | ||||||
|  |                 raise cv.Invalid( | ||||||
|  |                     f"Do not specify {CONF_PUMP_OFF_SWITCH_ID} or {CONF_PUMP_ON_SWITCH_ID} when using {CONF_PUMP_SWITCH_ID}" | ||||||
|  |                 ) | ||||||
|  |             if CONF_PUMP_PULSE_DURATION not in sprinkler_controller and ( | ||||||
|  |                 CONF_PUMP_OFF_SWITCH_ID in valve or CONF_PUMP_ON_SWITCH_ID in valve | ||||||
|  |             ): | ||||||
|  |                 raise cv.Invalid( | ||||||
|  |                     f"{CONF_PUMP_PULSE_DURATION} must be specified when using {CONF_PUMP_OFF_SWITCH_ID} and {CONF_PUMP_ON_SWITCH_ID}" | ||||||
|  |                 ) | ||||||
|  |             if ( | ||||||
|  |                 CONF_VALVE_OFF_SWITCH_ID in valve | ||||||
|  |                 and CONF_VALVE_ON_SWITCH_ID not in valve | ||||||
|  |             ) or ( | ||||||
|  |                 CONF_VALVE_ON_SWITCH_ID in valve | ||||||
|  |                 and CONF_VALVE_OFF_SWITCH_ID not in valve | ||||||
|  |             ): | ||||||
|  |                 raise cv.Invalid( | ||||||
|  |                     f"Both {CONF_VALVE_OFF_SWITCH_ID} and {CONF_VALVE_ON_SWITCH_ID} must be specified for latching valve configuration" | ||||||
|  |                 ) | ||||||
|  |             if CONF_VALVE_SWITCH_ID in valve and ( | ||||||
|  |                 CONF_VALVE_OFF_SWITCH_ID in valve or CONF_VALVE_ON_SWITCH_ID in valve | ||||||
|  |             ): | ||||||
|  |                 raise cv.Invalid( | ||||||
|  |                     f"Do not specify {CONF_VALVE_OFF_SWITCH_ID} or {CONF_VALVE_ON_SWITCH_ID} when using {CONF_VALVE_SWITCH_ID}" | ||||||
|  |                 ) | ||||||
|  |             if CONF_VALVE_PULSE_DURATION not in sprinkler_controller and ( | ||||||
|  |                 CONF_VALVE_OFF_SWITCH_ID in valve or CONF_VALVE_ON_SWITCH_ID in valve | ||||||
|  |             ): | ||||||
|  |                 raise cv.Invalid( | ||||||
|  |                     f"{CONF_VALVE_PULSE_DURATION} must be specified when using {CONF_VALVE_OFF_SWITCH_ID} and {CONF_VALVE_ON_SWITCH_ID}" | ||||||
|  |                 ) | ||||||
|  |             if ( | ||||||
|  |                 CONF_VALVE_SWITCH_ID not in valve | ||||||
|  |                 and CONF_VALVE_OFF_SWITCH_ID not in valve | ||||||
|  |                 and CONF_VALVE_ON_SWITCH_ID not in valve | ||||||
|  |             ): | ||||||
|  |                 raise cv.Invalid( | ||||||
|  |                     f"Either {CONF_VALVE_SWITCH_ID} or {CONF_VALVE_OFF_SWITCH_ID} and {CONF_VALVE_ON_SWITCH_ID} must be specified in valve configuration" | ||||||
|  |                 ) | ||||||
|  |     return config | ||||||
|  |  | ||||||
|  |  | ||||||
|  | SPRINKLER_ACTION_SCHEMA = maybe_simple_id( | ||||||
|  |     { | ||||||
|  |         cv.Required(CONF_ID): cv.use_id(Sprinkler), | ||||||
|  |     } | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | SPRINKLER_ACTION_REPEAT_SCHEMA = cv.maybe_simple_value( | ||||||
|  |     { | ||||||
|  |         cv.GenerateID(): cv.use_id(Sprinkler), | ||||||
|  |         cv.Required(CONF_REPEAT): cv.templatable(cv.positive_int), | ||||||
|  |     }, | ||||||
|  |     key=CONF_REPEAT, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | SPRINKLER_ACTION_SINGLE_VALVE_SCHEMA = cv.maybe_simple_value( | ||||||
|  |     { | ||||||
|  |         cv.GenerateID(): cv.use_id(Sprinkler), | ||||||
|  |         cv.Required(CONF_VALVE_NUMBER): cv.templatable(cv.positive_int), | ||||||
|  |     }, | ||||||
|  |     key=CONF_VALVE_NUMBER, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | SPRINKLER_ACTION_SET_MULTIPLIER_SCHEMA = cv.maybe_simple_value( | ||||||
|  |     { | ||||||
|  |         cv.GenerateID(): cv.use_id(Sprinkler), | ||||||
|  |         cv.Required(CONF_MULTIPLIER): cv.templatable(cv.positive_float), | ||||||
|  |     }, | ||||||
|  |     key=CONF_MULTIPLIER, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | SPRINKLER_ACTION_SET_RUN_DURATION_SCHEMA = cv.Schema( | ||||||
|  |     { | ||||||
|  |         cv.Required(CONF_ID): cv.use_id(Sprinkler), | ||||||
|  |         cv.Required(CONF_RUN_DURATION): cv.templatable(cv.positive_time_period_seconds), | ||||||
|  |         cv.Required(CONF_VALVE_NUMBER): cv.templatable(cv.positive_int), | ||||||
|  |     } | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | SPRINKLER_ACTION_QUEUE_VALVE_SCHEMA = cv.Schema( | ||||||
|  |     { | ||||||
|  |         cv.Required(CONF_ID): cv.use_id(Sprinkler), | ||||||
|  |         cv.Optional(CONF_RUN_DURATION, default=0): cv.templatable( | ||||||
|  |             cv.positive_time_period_seconds | ||||||
|  |         ), | ||||||
|  |         cv.Required(CONF_VALVE_NUMBER): cv.templatable(cv.positive_int), | ||||||
|  |     } | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | SPRINKLER_VALVE_SCHEMA = cv.Schema( | ||||||
|  |     { | ||||||
|  |         cv.Optional(CONF_ENABLE_SWITCH): cv.maybe_simple_value( | ||||||
|  |             switch.SWITCH_SCHEMA.extend( | ||||||
|  |                 cv.Schema( | ||||||
|  |                     { | ||||||
|  |                         cv.GenerateID(): cv.declare_id(SprinklerControllerSwitch), | ||||||
|  |                     } | ||||||
|  |                 ) | ||||||
|  |             ), | ||||||
|  |             key=CONF_NAME, | ||||||
|  |         ), | ||||||
|  |         cv.Optional(CONF_PUMP_OFF_SWITCH_ID): cv.use_id(switch.Switch), | ||||||
|  |         cv.Optional(CONF_PUMP_ON_SWITCH_ID): cv.use_id(switch.Switch), | ||||||
|  |         cv.Optional(CONF_PUMP_SWITCH_ID): cv.use_id(switch.Switch), | ||||||
|  |         cv.Required(CONF_RUN_DURATION): cv.positive_time_period_seconds, | ||||||
|  |         cv.Required(CONF_VALVE_SWITCH): cv.maybe_simple_value( | ||||||
|  |             switch.SWITCH_SCHEMA.extend( | ||||||
|  |                 cv.Schema( | ||||||
|  |                     { | ||||||
|  |                         cv.GenerateID(): cv.declare_id(SprinklerControllerSwitch), | ||||||
|  |                     } | ||||||
|  |                 ) | ||||||
|  |             ), | ||||||
|  |             key=CONF_NAME, | ||||||
|  |         ), | ||||||
|  |         cv.Optional(CONF_VALVE_OFF_SWITCH_ID): cv.use_id(switch.Switch), | ||||||
|  |         cv.Optional(CONF_VALVE_ON_SWITCH_ID): cv.use_id(switch.Switch), | ||||||
|  |         cv.Optional(CONF_VALVE_SWITCH_ID): cv.use_id(switch.Switch), | ||||||
|  |     } | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | SPRINKLER_CONTROLLER_SCHEMA = cv.Schema( | ||||||
|  |     { | ||||||
|  |         cv.GenerateID(): cv.declare_id(Sprinkler), | ||||||
|  |         cv.Optional(CONF_AUTO_ADVANCE_SWITCH): cv.maybe_simple_value( | ||||||
|  |             switch.SWITCH_SCHEMA.extend( | ||||||
|  |                 cv.Schema( | ||||||
|  |                     { | ||||||
|  |                         cv.GenerateID(): cv.declare_id(SprinklerControllerSwitch), | ||||||
|  |                     } | ||||||
|  |                 ) | ||||||
|  |             ), | ||||||
|  |             key=CONF_NAME, | ||||||
|  |         ), | ||||||
|  |         cv.Optional(CONF_MAIN_SWITCH): cv.maybe_simple_value( | ||||||
|  |             switch.SWITCH_SCHEMA.extend( | ||||||
|  |                 cv.Schema( | ||||||
|  |                     { | ||||||
|  |                         cv.GenerateID(): cv.declare_id(SprinklerControllerSwitch), | ||||||
|  |                     } | ||||||
|  |                 ) | ||||||
|  |             ), | ||||||
|  |             key=CONF_NAME, | ||||||
|  |         ), | ||||||
|  |         cv.Optional(CONF_QUEUE_ENABLE_SWITCH): cv.maybe_simple_value( | ||||||
|  |             switch.SWITCH_SCHEMA.extend( | ||||||
|  |                 cv.Schema( | ||||||
|  |                     { | ||||||
|  |                         cv.GenerateID(): cv.declare_id(SprinklerControllerSwitch), | ||||||
|  |                     } | ||||||
|  |                 ) | ||||||
|  |             ), | ||||||
|  |             key=CONF_NAME, | ||||||
|  |         ), | ||||||
|  |         cv.Optional(CONF_REVERSE_SWITCH): cv.maybe_simple_value( | ||||||
|  |             switch.SWITCH_SCHEMA.extend( | ||||||
|  |                 cv.Schema( | ||||||
|  |                     { | ||||||
|  |                         cv.GenerateID(): cv.declare_id(SprinklerControllerSwitch), | ||||||
|  |                     } | ||||||
|  |                 ) | ||||||
|  |             ), | ||||||
|  |             key=CONF_NAME, | ||||||
|  |         ), | ||||||
|  |         cv.Optional(CONF_MANUAL_SELECTION_DELAY): cv.positive_time_period_seconds, | ||||||
|  |         cv.Optional(CONF_REPEAT): cv.positive_int, | ||||||
|  |         cv.Optional(CONF_PUMP_PULSE_DURATION): cv.positive_time_period_milliseconds, | ||||||
|  |         cv.Optional(CONF_VALVE_PULSE_DURATION): cv.positive_time_period_milliseconds, | ||||||
|  |         cv.Exclusive( | ||||||
|  |             CONF_PUMP_START_PUMP_DELAY, "pump_start_xxxx_delay" | ||||||
|  |         ): cv.positive_time_period_seconds, | ||||||
|  |         cv.Exclusive( | ||||||
|  |             CONF_PUMP_STOP_PUMP_DELAY, "pump_stop_xxxx_delay" | ||||||
|  |         ): cv.positive_time_period_seconds, | ||||||
|  |         cv.Optional(CONF_PUMP_SWITCH_OFF_DURING_VALVE_OPEN_DELAY): cv.boolean, | ||||||
|  |         cv.Exclusive( | ||||||
|  |             CONF_PUMP_START_VALVE_DELAY, "pump_start_xxxx_delay" | ||||||
|  |         ): cv.positive_time_period_seconds, | ||||||
|  |         cv.Exclusive( | ||||||
|  |             CONF_PUMP_STOP_VALVE_DELAY, "pump_stop_xxxx_delay" | ||||||
|  |         ): cv.positive_time_period_seconds, | ||||||
|  |         cv.Exclusive( | ||||||
|  |             CONF_VALVE_OVERLAP, "open_delay/overlap" | ||||||
|  |         ): cv.positive_time_period_seconds, | ||||||
|  |         cv.Exclusive( | ||||||
|  |             CONF_VALVE_OPEN_DELAY, "open_delay/overlap" | ||||||
|  |         ): cv.positive_time_period_seconds, | ||||||
|  |         cv.Required(CONF_VALVES): cv.ensure_list(SPRINKLER_VALVE_SCHEMA), | ||||||
|  |     } | ||||||
|  | ).extend(cv.ENTITY_BASE_SCHEMA) | ||||||
|  |  | ||||||
|  | CONFIG_SCHEMA = cv.All( | ||||||
|  |     cv.ensure_list(SPRINKLER_CONTROLLER_SCHEMA), | ||||||
|  |     validate_sprinkler, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @automation.register_action( | ||||||
|  |     "sprinkler.set_multiplier", | ||||||
|  |     SetMultiplierAction, | ||||||
|  |     SPRINKLER_ACTION_SET_MULTIPLIER_SCHEMA, | ||||||
|  | ) | ||||||
|  | async def sprinkler_set_multiplier_to_code(config, action_id, template_arg, args): | ||||||
|  |     paren = await cg.get_variable(config[CONF_ID]) | ||||||
|  |     var = cg.new_Pvariable(action_id, template_arg, paren) | ||||||
|  |     template_ = await cg.templatable(config[CONF_MULTIPLIER], args, cg.float_) | ||||||
|  |     cg.add(var.set_multiplier(template_)) | ||||||
|  |     return var | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @automation.register_action( | ||||||
|  |     "sprinkler.queue_valve", | ||||||
|  |     QueueValveAction, | ||||||
|  |     SPRINKLER_ACTION_QUEUE_VALVE_SCHEMA, | ||||||
|  | ) | ||||||
|  | async def sprinkler_set_queued_valve_to_code(config, action_id, template_arg, args): | ||||||
|  |     paren = await cg.get_variable(config[CONF_ID]) | ||||||
|  |     var = cg.new_Pvariable(action_id, template_arg, paren) | ||||||
|  |     template_ = await cg.templatable(config[CONF_VALVE_NUMBER], args, cg.uint8) | ||||||
|  |     cg.add(var.set_valve_number(template_)) | ||||||
|  |     template_ = await cg.templatable(config[CONF_RUN_DURATION], args, cg.uint32) | ||||||
|  |     cg.add(var.set_valve_run_duration(template_)) | ||||||
|  |     return var | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @automation.register_action( | ||||||
|  |     "sprinkler.set_repeat", | ||||||
|  |     SetRepeatAction, | ||||||
|  |     SPRINKLER_ACTION_REPEAT_SCHEMA, | ||||||
|  | ) | ||||||
|  | async def sprinkler_set_repeat_to_code(config, action_id, template_arg, args): | ||||||
|  |     paren = await cg.get_variable(config[CONF_ID]) | ||||||
|  |     var = cg.new_Pvariable(action_id, template_arg, paren) | ||||||
|  |     template_ = await cg.templatable(config[CONF_REPEAT], args, cg.float_) | ||||||
|  |     cg.add(var.set_repeat(template_)) | ||||||
|  |     return var | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @automation.register_action( | ||||||
|  |     "sprinkler.set_valve_run_duration", | ||||||
|  |     SetRunDurationAction, | ||||||
|  |     SPRINKLER_ACTION_SET_RUN_DURATION_SCHEMA, | ||||||
|  | ) | ||||||
|  | async def sprinkler_set_valve_run_duration_to_code( | ||||||
|  |     config, action_id, template_arg, args | ||||||
|  | ): | ||||||
|  |     paren = await cg.get_variable(config[CONF_ID]) | ||||||
|  |     var = cg.new_Pvariable(action_id, template_arg, paren) | ||||||
|  |     template_ = await cg.templatable(config[CONF_VALVE_NUMBER], args, cg.uint8) | ||||||
|  |     cg.add(var.set_valve_number(template_)) | ||||||
|  |     template_ = await cg.templatable(config[CONF_RUN_DURATION], args, cg.uint32) | ||||||
|  |     cg.add(var.set_valve_run_duration(template_)) | ||||||
|  |     return var | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @automation.register_action( | ||||||
|  |     "sprinkler.start_from_queue", StartFromQueueAction, SPRINKLER_ACTION_SCHEMA | ||||||
|  | ) | ||||||
|  | async def sprinkler_start_from_queue_to_code(config, action_id, template_arg, args): | ||||||
|  |     paren = await cg.get_variable(config[CONF_ID]) | ||||||
|  |     return cg.new_Pvariable(action_id, template_arg, paren) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @automation.register_action( | ||||||
|  |     "sprinkler.start_full_cycle", StartFullCycleAction, SPRINKLER_ACTION_SCHEMA | ||||||
|  | ) | ||||||
|  | async def sprinkler_start_full_cycle_to_code(config, action_id, template_arg, args): | ||||||
|  |     paren = await cg.get_variable(config[CONF_ID]) | ||||||
|  |     return cg.new_Pvariable(action_id, template_arg, paren) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @automation.register_action( | ||||||
|  |     "sprinkler.start_single_valve", | ||||||
|  |     StartSingleValveAction, | ||||||
|  |     SPRINKLER_ACTION_SINGLE_VALVE_SCHEMA, | ||||||
|  | ) | ||||||
|  | async def sprinkler_start_single_valve_to_code(config, action_id, template_arg, args): | ||||||
|  |     paren = await cg.get_variable(config[CONF_ID]) | ||||||
|  |     var = cg.new_Pvariable(action_id, template_arg, paren) | ||||||
|  |     template_ = await cg.templatable(config[CONF_VALVE_NUMBER], args, cg.uint8) | ||||||
|  |     cg.add(var.set_valve_to_start(template_)) | ||||||
|  |     return var | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @automation.register_action( | ||||||
|  |     "sprinkler.clear_queued_valves", ClearQueuedValvesAction, SPRINKLER_ACTION_SCHEMA | ||||||
|  | ) | ||||||
|  | @automation.register_action( | ||||||
|  |     "sprinkler.next_valve", NextValveAction, SPRINKLER_ACTION_SCHEMA | ||||||
|  | ) | ||||||
|  | @automation.register_action( | ||||||
|  |     "sprinkler.previous_valve", PreviousValveAction, SPRINKLER_ACTION_SCHEMA | ||||||
|  | ) | ||||||
|  | @automation.register_action("sprinkler.pause", PauseAction, SPRINKLER_ACTION_SCHEMA) | ||||||
|  | @automation.register_action("sprinkler.resume", ResumeAction, SPRINKLER_ACTION_SCHEMA) | ||||||
|  | @automation.register_action( | ||||||
|  |     "sprinkler.resume_or_start_full_cycle", ResumeOrStartAction, SPRINKLER_ACTION_SCHEMA | ||||||
|  | ) | ||||||
|  | @automation.register_action( | ||||||
|  |     "sprinkler.shutdown", ShutdownAction, SPRINKLER_ACTION_SCHEMA | ||||||
|  | ) | ||||||
|  | async def sprinkler_simple_action_to_code(config, action_id, template_arg, args): | ||||||
|  |     paren = await cg.get_variable(config[CONF_ID]) | ||||||
|  |     return cg.new_Pvariable(action_id, template_arg, paren) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | async def to_code(config): | ||||||
|  |     for sprinkler_controller in config: | ||||||
|  |         if len(sprinkler_controller[CONF_VALVES]) > 1: | ||||||
|  |             var = cg.new_Pvariable( | ||||||
|  |                 sprinkler_controller[CONF_ID], | ||||||
|  |                 sprinkler_controller[CONF_MAIN_SWITCH][CONF_NAME], | ||||||
|  |             ) | ||||||
|  |         else: | ||||||
|  |             var = cg.new_Pvariable( | ||||||
|  |                 sprinkler_controller[CONF_ID], | ||||||
|  |                 sprinkler_controller[CONF_VALVES][0][CONF_VALVE_SWITCH][CONF_NAME], | ||||||
|  |             ) | ||||||
|  |         await cg.register_component(var, sprinkler_controller) | ||||||
|  |  | ||||||
|  |         if len(sprinkler_controller[CONF_VALVES]) > 1: | ||||||
|  |             sw_var = await switch.new_switch(sprinkler_controller[CONF_MAIN_SWITCH]) | ||||||
|  |             await cg.register_component(sw_var, sprinkler_controller[CONF_MAIN_SWITCH]) | ||||||
|  |             cg.add(var.set_controller_main_switch(sw_var)) | ||||||
|  |  | ||||||
|  |             sw_aa_var = await switch.new_switch( | ||||||
|  |                 sprinkler_controller[CONF_AUTO_ADVANCE_SWITCH] | ||||||
|  |             ) | ||||||
|  |             await cg.register_component( | ||||||
|  |                 sw_aa_var, sprinkler_controller[CONF_AUTO_ADVANCE_SWITCH] | ||||||
|  |             ) | ||||||
|  |             cg.add(var.set_controller_auto_adv_switch(sw_aa_var)) | ||||||
|  |  | ||||||
|  |             if CONF_QUEUE_ENABLE_SWITCH in sprinkler_controller: | ||||||
|  |                 sw_qen_var = await switch.new_switch( | ||||||
|  |                     sprinkler_controller[CONF_QUEUE_ENABLE_SWITCH] | ||||||
|  |                 ) | ||||||
|  |                 await cg.register_component( | ||||||
|  |                     sw_qen_var, sprinkler_controller[CONF_QUEUE_ENABLE_SWITCH] | ||||||
|  |                 ) | ||||||
|  |                 cg.add(var.set_controller_queue_enable_switch(sw_qen_var)) | ||||||
|  |  | ||||||
|  |             if CONF_REVERSE_SWITCH in sprinkler_controller: | ||||||
|  |                 sw_rev_var = await switch.new_switch( | ||||||
|  |                     sprinkler_controller[CONF_REVERSE_SWITCH] | ||||||
|  |                 ) | ||||||
|  |                 await cg.register_component( | ||||||
|  |                     sw_rev_var, sprinkler_controller[CONF_REVERSE_SWITCH] | ||||||
|  |                 ) | ||||||
|  |                 cg.add(var.set_controller_reverse_switch(sw_rev_var)) | ||||||
|  |  | ||||||
|  |         for valve in sprinkler_controller[CONF_VALVES]: | ||||||
|  |             sw_valve_var = await switch.new_switch(valve[CONF_VALVE_SWITCH]) | ||||||
|  |             await cg.register_component(sw_valve_var, valve[CONF_VALVE_SWITCH]) | ||||||
|  |  | ||||||
|  |             if ( | ||||||
|  |                 CONF_ENABLE_SWITCH in valve | ||||||
|  |                 and len(sprinkler_controller[CONF_VALVES]) > 1 | ||||||
|  |             ): | ||||||
|  |                 sw_en_var = await switch.new_switch(valve[CONF_ENABLE_SWITCH]) | ||||||
|  |                 await cg.register_component(sw_en_var, valve[CONF_ENABLE_SWITCH]) | ||||||
|  |  | ||||||
|  |                 cg.add(var.add_valve(sw_valve_var, sw_en_var)) | ||||||
|  |             else: | ||||||
|  |                 cg.add(var.add_valve(sw_valve_var)) | ||||||
|  |  | ||||||
|  |         if CONF_MANUAL_SELECTION_DELAY in sprinkler_controller: | ||||||
|  |             cg.add( | ||||||
|  |                 var.set_manual_selection_delay( | ||||||
|  |                     sprinkler_controller[CONF_MANUAL_SELECTION_DELAY] | ||||||
|  |                 ) | ||||||
|  |             ) | ||||||
|  |  | ||||||
|  |         if CONF_REPEAT in sprinkler_controller: | ||||||
|  |             cg.add(var.set_repeat(sprinkler_controller[CONF_REPEAT])) | ||||||
|  |  | ||||||
|  |         if CONF_VALVE_OVERLAP in sprinkler_controller: | ||||||
|  |             cg.add(var.set_valve_overlap(sprinkler_controller[CONF_VALVE_OVERLAP])) | ||||||
|  |  | ||||||
|  |         if CONF_VALVE_OPEN_DELAY in sprinkler_controller: | ||||||
|  |             cg.add( | ||||||
|  |                 var.set_valve_open_delay(sprinkler_controller[CONF_VALVE_OPEN_DELAY]) | ||||||
|  |             ) | ||||||
|  |  | ||||||
|  |         if CONF_PUMP_START_PUMP_DELAY in sprinkler_controller: | ||||||
|  |             cg.add( | ||||||
|  |                 var.set_pump_start_delay( | ||||||
|  |                     sprinkler_controller[CONF_PUMP_START_PUMP_DELAY] | ||||||
|  |                 ) | ||||||
|  |             ) | ||||||
|  |  | ||||||
|  |         if CONF_PUMP_STOP_PUMP_DELAY in sprinkler_controller: | ||||||
|  |             cg.add( | ||||||
|  |                 var.set_pump_stop_delay(sprinkler_controller[CONF_PUMP_STOP_PUMP_DELAY]) | ||||||
|  |             ) | ||||||
|  |  | ||||||
|  |         if CONF_PUMP_START_VALVE_DELAY in sprinkler_controller: | ||||||
|  |             cg.add( | ||||||
|  |                 var.set_valve_start_delay( | ||||||
|  |                     sprinkler_controller[CONF_PUMP_START_VALVE_DELAY] | ||||||
|  |                 ) | ||||||
|  |             ) | ||||||
|  |  | ||||||
|  |         if CONF_PUMP_STOP_VALVE_DELAY in sprinkler_controller: | ||||||
|  |             cg.add( | ||||||
|  |                 var.set_valve_stop_delay( | ||||||
|  |                     sprinkler_controller[CONF_PUMP_STOP_VALVE_DELAY] | ||||||
|  |                 ) | ||||||
|  |             ) | ||||||
|  |  | ||||||
|  |         if CONF_PUMP_SWITCH_OFF_DURING_VALVE_OPEN_DELAY in sprinkler_controller: | ||||||
|  |             cg.add( | ||||||
|  |                 var.set_pump_switch_off_during_valve_open_delay( | ||||||
|  |                     sprinkler_controller[CONF_PUMP_SWITCH_OFF_DURING_VALVE_OPEN_DELAY] | ||||||
|  |                 ) | ||||||
|  |             ) | ||||||
|  |  | ||||||
|  |     for sprinkler_controller in config: | ||||||
|  |         var = await cg.get_variable(sprinkler_controller[CONF_ID]) | ||||||
|  |         for valve_index, valve in enumerate(sprinkler_controller[CONF_VALVES]): | ||||||
|  |             if CONF_VALVE_SWITCH_ID in valve: | ||||||
|  |                 valve_switch = await cg.get_variable(valve[CONF_VALVE_SWITCH_ID]) | ||||||
|  |                 cg.add( | ||||||
|  |                     var.configure_valve_switch( | ||||||
|  |                         valve_index, valve_switch, valve[CONF_RUN_DURATION] | ||||||
|  |                     ) | ||||||
|  |                 ) | ||||||
|  |             elif CONF_VALVE_OFF_SWITCH_ID in valve and CONF_VALVE_ON_SWITCH_ID in valve: | ||||||
|  |                 valve_switch_off = await cg.get_variable( | ||||||
|  |                     valve[CONF_VALVE_OFF_SWITCH_ID] | ||||||
|  |                 ) | ||||||
|  |                 valve_switch_on = await cg.get_variable(valve[CONF_VALVE_ON_SWITCH_ID]) | ||||||
|  |                 cg.add( | ||||||
|  |                     var.configure_valve_switch_pulsed( | ||||||
|  |                         valve_index, | ||||||
|  |                         valve_switch_off, | ||||||
|  |                         valve_switch_on, | ||||||
|  |                         sprinkler_controller[CONF_VALVE_PULSE_DURATION], | ||||||
|  |                         valve[CONF_RUN_DURATION], | ||||||
|  |                     ) | ||||||
|  |                 ) | ||||||
|  |  | ||||||
|  |             if CONF_PUMP_SWITCH_ID in valve: | ||||||
|  |                 pump = await cg.get_variable(valve[CONF_PUMP_SWITCH_ID]) | ||||||
|  |                 cg.add(var.configure_valve_pump_switch(valve_index, pump)) | ||||||
|  |             elif CONF_PUMP_OFF_SWITCH_ID in valve and CONF_PUMP_ON_SWITCH_ID in valve: | ||||||
|  |                 pump_off = await cg.get_variable(valve[CONF_PUMP_OFF_SWITCH_ID]) | ||||||
|  |                 pump_on = await cg.get_variable(valve[CONF_PUMP_ON_SWITCH_ID]) | ||||||
|  |                 cg.add( | ||||||
|  |                     var.configure_valve_pump_switch_pulsed( | ||||||
|  |                         valve_index, | ||||||
|  |                         pump_off, | ||||||
|  |                         pump_on, | ||||||
|  |                         sprinkler_controller[CONF_PUMP_PULSE_DURATION], | ||||||
|  |                     ) | ||||||
|  |                 ) | ||||||
|  |  | ||||||
|  |     for sprinkler_controller in config: | ||||||
|  |         var = await cg.get_variable(sprinkler_controller[CONF_ID]) | ||||||
|  |         for controller_to_add in config: | ||||||
|  |             if sprinkler_controller[CONF_ID] != controller_to_add[CONF_ID]: | ||||||
|  |                 cg.add( | ||||||
|  |                     var.add_controller( | ||||||
|  |                         await cg.get_variable(controller_to_add[CONF_ID]) | ||||||
|  |                     ) | ||||||
|  |                 ) | ||||||
							
								
								
									
										169
									
								
								esphome/components/sprinkler/automation.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										169
									
								
								esphome/components/sprinkler/automation.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,169 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "esphome/core/automation.h" | ||||||
|  | #include "esphome/core/component.h" | ||||||
|  | #include "esphome/components/sprinkler/sprinkler.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace sprinkler { | ||||||
|  |  | ||||||
|  | template<typename... Ts> class SetMultiplierAction : public Action<Ts...> { | ||||||
|  |  public: | ||||||
|  |   explicit SetMultiplierAction(Sprinkler *a_sprinkler) : sprinkler_(a_sprinkler) {} | ||||||
|  |  | ||||||
|  |   TEMPLATABLE_VALUE(float, multiplier) | ||||||
|  |  | ||||||
|  |   void play(Ts... x) override { this->sprinkler_->set_multiplier(this->multiplier_.optional_value(x...)); } | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   Sprinkler *sprinkler_; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<typename... Ts> class QueueValveAction : public Action<Ts...> { | ||||||
|  |  public: | ||||||
|  |   explicit QueueValveAction(Sprinkler *a_sprinkler) : sprinkler_(a_sprinkler) {} | ||||||
|  |  | ||||||
|  |   TEMPLATABLE_VALUE(size_t, valve_number) | ||||||
|  |   TEMPLATABLE_VALUE(uint32_t, valve_run_duration) | ||||||
|  |  | ||||||
|  |   void play(Ts... x) override { | ||||||
|  |     this->sprinkler_->queue_valve(this->valve_number_.optional_value(x...), | ||||||
|  |                                   this->valve_run_duration_.optional_value(x...)); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   Sprinkler *sprinkler_; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<typename... Ts> class ClearQueuedValvesAction : public Action<Ts...> { | ||||||
|  |  public: | ||||||
|  |   explicit ClearQueuedValvesAction(Sprinkler *a_sprinkler) : sprinkler_(a_sprinkler) {} | ||||||
|  |  | ||||||
|  |   void play(Ts... x) override { this->sprinkler_->clear_queued_valves(); } | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   Sprinkler *sprinkler_; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<typename... Ts> class SetRepeatAction : public Action<Ts...> { | ||||||
|  |  public: | ||||||
|  |   explicit SetRepeatAction(Sprinkler *a_sprinkler) : sprinkler_(a_sprinkler) {} | ||||||
|  |  | ||||||
|  |   TEMPLATABLE_VALUE(uint32_t, repeat) | ||||||
|  |  | ||||||
|  |   void play(Ts... x) override { this->sprinkler_->set_repeat(this->repeat_.optional_value(x...)); } | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   Sprinkler *sprinkler_; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<typename... Ts> class SetRunDurationAction : public Action<Ts...> { | ||||||
|  |  public: | ||||||
|  |   explicit SetRunDurationAction(Sprinkler *a_sprinkler) : sprinkler_(a_sprinkler) {} | ||||||
|  |  | ||||||
|  |   TEMPLATABLE_VALUE(size_t, valve_number) | ||||||
|  |   TEMPLATABLE_VALUE(uint32_t, valve_run_duration) | ||||||
|  |  | ||||||
|  |   void play(Ts... x) override { | ||||||
|  |     this->sprinkler_->set_valve_run_duration(this->valve_number_.optional_value(x...), | ||||||
|  |                                              this->valve_run_duration_.optional_value(x...)); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   Sprinkler *sprinkler_; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<typename... Ts> class StartFromQueueAction : public Action<Ts...> { | ||||||
|  |  public: | ||||||
|  |   explicit StartFromQueueAction(Sprinkler *a_sprinkler) : sprinkler_(a_sprinkler) {} | ||||||
|  |  | ||||||
|  |   void play(Ts... x) override { this->sprinkler_->start_from_queue(); } | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   Sprinkler *sprinkler_; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<typename... Ts> class StartFullCycleAction : public Action<Ts...> { | ||||||
|  |  public: | ||||||
|  |   explicit StartFullCycleAction(Sprinkler *a_sprinkler) : sprinkler_(a_sprinkler) {} | ||||||
|  |  | ||||||
|  |   void play(Ts... x) override { this->sprinkler_->start_full_cycle(); } | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   Sprinkler *sprinkler_; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<typename... Ts> class StartSingleValveAction : public Action<Ts...> { | ||||||
|  |  public: | ||||||
|  |   explicit StartSingleValveAction(Sprinkler *a_sprinkler) : sprinkler_(a_sprinkler) {} | ||||||
|  |  | ||||||
|  |   TEMPLATABLE_VALUE(size_t, valve_to_start) | ||||||
|  |  | ||||||
|  |   void play(Ts... x) override { this->sprinkler_->start_single_valve(this->valve_to_start_.optional_value(x...)); } | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   Sprinkler *sprinkler_; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<typename... Ts> class ShutdownAction : public Action<Ts...> { | ||||||
|  |  public: | ||||||
|  |   explicit ShutdownAction(Sprinkler *a_sprinkler) : sprinkler_(a_sprinkler) {} | ||||||
|  |  | ||||||
|  |   void play(Ts... x) override { this->sprinkler_->shutdown(); } | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   Sprinkler *sprinkler_; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<typename... Ts> class NextValveAction : public Action<Ts...> { | ||||||
|  |  public: | ||||||
|  |   explicit NextValveAction(Sprinkler *a_sprinkler) : sprinkler_(a_sprinkler) {} | ||||||
|  |  | ||||||
|  |   void play(Ts... x) override { this->sprinkler_->next_valve(); } | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   Sprinkler *sprinkler_; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<typename... Ts> class PreviousValveAction : public Action<Ts...> { | ||||||
|  |  public: | ||||||
|  |   explicit PreviousValveAction(Sprinkler *a_sprinkler) : sprinkler_(a_sprinkler) {} | ||||||
|  |  | ||||||
|  |   void play(Ts... x) override { this->sprinkler_->previous_valve(); } | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   Sprinkler *sprinkler_; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<typename... Ts> class PauseAction : public Action<Ts...> { | ||||||
|  |  public: | ||||||
|  |   explicit PauseAction(Sprinkler *a_sprinkler) : sprinkler_(a_sprinkler) {} | ||||||
|  |  | ||||||
|  |   void play(Ts... x) override { this->sprinkler_->pause(); } | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   Sprinkler *sprinkler_; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<typename... Ts> class ResumeAction : public Action<Ts...> { | ||||||
|  |  public: | ||||||
|  |   explicit ResumeAction(Sprinkler *a_sprinkler) : sprinkler_(a_sprinkler) {} | ||||||
|  |  | ||||||
|  |   void play(Ts... x) override { this->sprinkler_->resume(); } | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   Sprinkler *sprinkler_; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<typename... Ts> class ResumeOrStartAction : public Action<Ts...> { | ||||||
|  |  public: | ||||||
|  |   explicit ResumeOrStartAction(Sprinkler *a_sprinkler) : sprinkler_(a_sprinkler) {} | ||||||
|  |  | ||||||
|  |   void play(Ts... x) override { this->sprinkler_->resume_or_start_full_cycle(); } | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   Sprinkler *sprinkler_; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | }  // namespace sprinkler | ||||||
|  | }  // namespace esphome | ||||||
							
								
								
									
										1347
									
								
								esphome/components/sprinkler/sprinkler.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1347
									
								
								esphome/components/sprinkler/sprinkler.cpp
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										528
									
								
								esphome/components/sprinkler/sprinkler.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										528
									
								
								esphome/components/sprinkler/sprinkler.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,528 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "esphome/core/automation.h" | ||||||
|  | #include "esphome/core/component.h" | ||||||
|  | #include "esphome/core/hal.h" | ||||||
|  | #include "esphome/components/switch/switch.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace sprinkler { | ||||||
|  |  | ||||||
|  | enum SprinklerState : uint8_t { | ||||||
|  |   // NOTE: these states are used by both SprinklerValveOperator and Sprinkler (the controller)! | ||||||
|  |   IDLE,      // system/valve is off | ||||||
|  |   STARTING,  // system/valve is starting/"half open" -- either pump or valve is on, but the remaining pump/valve is not | ||||||
|  |   ACTIVE,    // system/valve is running its cycle | ||||||
|  |   STOPPING,  // system/valve is stopping/"half open" -- either pump or valve is on, but the remaining pump/valve is not | ||||||
|  |   BYPASS     // used by SprinklerValveOperator to ignore the instance checking pump status | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | enum SprinklerTimerIndex : uint8_t { | ||||||
|  |   TIMER_SM = 0, | ||||||
|  |   TIMER_VALVE_SELECTION = 1, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class Sprinkler;                  // this component | ||||||
|  | class SprinklerControllerSwitch;  // switches that appear in the front end; based on switch core | ||||||
|  | class SprinklerSwitch;            // switches representing any valve or pump; provides abstraction for latching valves | ||||||
|  | class SprinklerValveOperator;     // manages all switching on/off of valves and associated pumps | ||||||
|  | class SprinklerValveRunRequest;   // tells the sprinkler controller what valve to run and for how long as well as what | ||||||
|  |                                   //  SprinklerValveOperator is handling it | ||||||
|  | template<typename... Ts> class StartSingleValveAction; | ||||||
|  | template<typename... Ts> class ShutdownAction; | ||||||
|  | template<typename... Ts> class ResumeOrStartAction; | ||||||
|  |  | ||||||
|  | class SprinklerSwitch { | ||||||
|  |  public: | ||||||
|  |   SprinklerSwitch(); | ||||||
|  |   SprinklerSwitch(switch_::Switch *sprinkler_switch); | ||||||
|  |   SprinklerSwitch(switch_::Switch *off_switch, switch_::Switch *on_switch, uint32_t pulse_duration); | ||||||
|  |  | ||||||
|  |   bool is_latching_valve();  // returns true if configured as a latching valve | ||||||
|  |   void loop();               // called as a part of loop(), used for latching valve pulses | ||||||
|  |   uint32_t pulse_duration() { return this->pulse_duration_; } | ||||||
|  |   bool state();  // returns the switch's current state | ||||||
|  |   void set_off_switch(switch_::Switch *off_switch) { this->off_switch_ = off_switch; } | ||||||
|  |   void set_on_switch(switch_::Switch *on_switch) { this->on_switch_ = on_switch; } | ||||||
|  |   void set_pulse_duration(uint32_t pulse_duration) { this->pulse_duration_ = pulse_duration; } | ||||||
|  |   void sync_valve_state( | ||||||
|  |       bool latch_state);  // syncs internal state to switch; if latching valve, sets state to latch_state | ||||||
|  |   void turn_off();        // sets internal flag and actuates the switch | ||||||
|  |   void turn_on();         // sets internal flag and actuates the switch | ||||||
|  |   switch_::Switch *off_switch() { return this->off_switch_; } | ||||||
|  |   switch_::Switch *on_switch() { return this->on_switch_; } | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   bool state_{false}; | ||||||
|  |   uint32_t pulse_duration_{0}; | ||||||
|  |   uint64_t pinned_millis_{0}; | ||||||
|  |   switch_::Switch *off_switch_{nullptr};  // only used for latching valves | ||||||
|  |   switch_::Switch *on_switch_{nullptr};   // used for both latching and non-latching valves | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | struct SprinklerQueueItem { | ||||||
|  |   size_t valve_number; | ||||||
|  |   uint32_t run_duration; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | struct SprinklerTimer { | ||||||
|  |   const std::string name; | ||||||
|  |   bool active; | ||||||
|  |   uint32_t time; | ||||||
|  |   uint32_t start_time; | ||||||
|  |   std::function<void()> func; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | struct SprinklerValve { | ||||||
|  |   SprinklerControllerSwitch *controller_switch; | ||||||
|  |   SprinklerControllerSwitch *enable_switch; | ||||||
|  |   SprinklerSwitch valve_switch; | ||||||
|  |   uint32_t run_duration; | ||||||
|  |   optional<size_t> pump_switch_index; | ||||||
|  |   bool valve_cycle_complete; | ||||||
|  |   std::unique_ptr<ShutdownAction<>> valve_shutdown_action; | ||||||
|  |   std::unique_ptr<StartSingleValveAction<>> valve_resumeorstart_action; | ||||||
|  |   std::unique_ptr<Automation<>> valve_turn_off_automation; | ||||||
|  |   std::unique_ptr<Automation<>> valve_turn_on_automation; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class SprinklerControllerSwitch : public switch_::Switch, public Component { | ||||||
|  |  public: | ||||||
|  |   SprinklerControllerSwitch(); | ||||||
|  |  | ||||||
|  |   void setup() override; | ||||||
|  |   void dump_config() override; | ||||||
|  |  | ||||||
|  |   void set_state_lambda(std::function<optional<bool>()> &&f); | ||||||
|  |   void set_restore_state(bool restore_state); | ||||||
|  |   Trigger<> *get_turn_on_trigger() const; | ||||||
|  |   Trigger<> *get_turn_off_trigger() const; | ||||||
|  |   void set_optimistic(bool optimistic); | ||||||
|  |   void set_assumed_state(bool assumed_state); | ||||||
|  |   void loop() override; | ||||||
|  |  | ||||||
|  |   float get_setup_priority() const override; | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   bool assumed_state() override; | ||||||
|  |  | ||||||
|  |   void write_state(bool state) override; | ||||||
|  |  | ||||||
|  |   optional<std::function<optional<bool>()>> f_; | ||||||
|  |   bool optimistic_{false}; | ||||||
|  |   bool assumed_state_{false}; | ||||||
|  |   Trigger<> *turn_on_trigger_; | ||||||
|  |   Trigger<> *turn_off_trigger_; | ||||||
|  |   Trigger<> *prev_trigger_{nullptr}; | ||||||
|  |   bool restore_state_{false}; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class SprinklerValveOperator { | ||||||
|  |  public: | ||||||
|  |   SprinklerValveOperator(); | ||||||
|  |   SprinklerValveOperator(SprinklerValve *valve, Sprinkler *controller); | ||||||
|  |   void loop(); | ||||||
|  |   void set_controller(Sprinkler *controller); | ||||||
|  |   void set_valve(SprinklerValve *valve); | ||||||
|  |   void set_run_duration(uint32_t run_duration);  // set the desired run duration in seconds | ||||||
|  |   void set_start_delay(uint32_t start_delay, bool start_delay_is_valve_delay); | ||||||
|  |   void set_stop_delay(uint32_t stop_delay, bool stop_delay_is_valve_delay); | ||||||
|  |   void start(); | ||||||
|  |   void stop(); | ||||||
|  |   uint32_t run_duration();         // returns the desired run duration in seconds | ||||||
|  |   uint32_t time_remaining();       // returns seconds remaining (does not include stop_delay_) | ||||||
|  |   SprinklerState state();          // returns the valve's state/status | ||||||
|  |   SprinklerSwitch *pump_switch();  // returns this SprinklerValveOperator's pump's SprinklerSwitch | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   void pump_off_(); | ||||||
|  |   void pump_on_(); | ||||||
|  |   void valve_off_(); | ||||||
|  |   void valve_on_(); | ||||||
|  |   void kill_(); | ||||||
|  |   void run_(); | ||||||
|  |   bool start_delay_is_valve_delay_{false}; | ||||||
|  |   bool stop_delay_is_valve_delay_{false}; | ||||||
|  |   uint32_t start_delay_{0}; | ||||||
|  |   uint32_t stop_delay_{0}; | ||||||
|  |   uint32_t run_duration_{0}; | ||||||
|  |   uint64_t pinned_millis_{0}; | ||||||
|  |   Sprinkler *controller_{nullptr}; | ||||||
|  |   SprinklerValve *valve_{nullptr}; | ||||||
|  |   SprinklerState state_{IDLE}; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class SprinklerValveRunRequest { | ||||||
|  |  public: | ||||||
|  |   SprinklerValveRunRequest(); | ||||||
|  |   SprinklerValveRunRequest(size_t valve_number, uint32_t run_duration, SprinklerValveOperator *valve_op); | ||||||
|  |   bool has_request(); | ||||||
|  |   bool has_valve_operator(); | ||||||
|  |   void set_run_duration(uint32_t run_duration); | ||||||
|  |   void set_valve(size_t valve_number); | ||||||
|  |   void set_valve_operator(SprinklerValveOperator *valve_op); | ||||||
|  |   void reset(); | ||||||
|  |   uint32_t run_duration(); | ||||||
|  |   size_t valve(); | ||||||
|  |   optional<size_t> valve_as_opt(); | ||||||
|  |   SprinklerValveOperator *valve_operator(); | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   bool has_valve_{false}; | ||||||
|  |   size_t valve_number_{0}; | ||||||
|  |   uint32_t run_duration_{0}; | ||||||
|  |   SprinklerValveOperator *valve_op_{nullptr}; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class Sprinkler : public Component, public EntityBase { | ||||||
|  |  public: | ||||||
|  |   Sprinkler(); | ||||||
|  |   Sprinkler(const std::string &name); | ||||||
|  |  | ||||||
|  |   void setup() override; | ||||||
|  |   void loop() override; | ||||||
|  |   void dump_config() override; | ||||||
|  |  | ||||||
|  |   /// add a valve to the controller | ||||||
|  |   void add_valve(SprinklerControllerSwitch *valve_sw, SprinklerControllerSwitch *enable_sw = nullptr); | ||||||
|  |  | ||||||
|  |   /// add another controller to the controller so it can check if pumps/main valves are in use | ||||||
|  |   void add_controller(Sprinkler *other_controller); | ||||||
|  |  | ||||||
|  |   /// configure important controller switches | ||||||
|  |   void set_controller_main_switch(SprinklerControllerSwitch *controller_switch); | ||||||
|  |   void set_controller_auto_adv_switch(SprinklerControllerSwitch *auto_adv_switch); | ||||||
|  |   void set_controller_queue_enable_switch(SprinklerControllerSwitch *queue_enable_switch); | ||||||
|  |   void set_controller_reverse_switch(SprinklerControllerSwitch *reverse_switch); | ||||||
|  |  | ||||||
|  |   /// configure a valve's switch object and run duration. run_duration is time in seconds. | ||||||
|  |   void configure_valve_switch(size_t valve_number, switch_::Switch *valve_switch, uint32_t run_duration); | ||||||
|  |   void configure_valve_switch_pulsed(size_t valve_number, switch_::Switch *valve_switch_off, | ||||||
|  |                                      switch_::Switch *valve_switch_on, uint32_t pulse_duration, uint32_t run_duration); | ||||||
|  |  | ||||||
|  |   /// configure a valve's associated pump switch object | ||||||
|  |   void configure_valve_pump_switch(size_t valve_number, switch_::Switch *pump_switch); | ||||||
|  |   void configure_valve_pump_switch_pulsed(size_t valve_number, switch_::Switch *pump_switch_off, | ||||||
|  |                                           switch_::Switch *pump_switch_on, uint32_t pulse_duration); | ||||||
|  |  | ||||||
|  |   /// value multiplied by configured run times -- used to extend or shorten the cycle | ||||||
|  |   void set_multiplier(optional<float> multiplier); | ||||||
|  |  | ||||||
|  |   /// set how long the pump should start after the valve (when the pump is starting) | ||||||
|  |   void set_pump_start_delay(uint32_t start_delay); | ||||||
|  |  | ||||||
|  |   /// set how long the pump should stop after the valve (when the pump is starting) | ||||||
|  |   void set_pump_stop_delay(uint32_t stop_delay); | ||||||
|  |  | ||||||
|  |   /// set how long the valve should start after the pump (when the pump is stopping) | ||||||
|  |   void set_valve_start_delay(uint32_t start_delay); | ||||||
|  |  | ||||||
|  |   /// set how long the valve should stop after the pump (when the pump is stopping) | ||||||
|  |   void set_valve_stop_delay(uint32_t stop_delay); | ||||||
|  |  | ||||||
|  |   /// if pump_switch_off_during_valve_open_delay is true, the controller will switch off the pump during the | ||||||
|  |   ///  valve_open_delay interval | ||||||
|  |   void set_pump_switch_off_during_valve_open_delay(bool pump_switch_off_during_valve_open_delay); | ||||||
|  |  | ||||||
|  |   /// set how long the controller should wait to open/switch on the valve after it becomes active | ||||||
|  |   void set_valve_open_delay(uint32_t valve_open_delay); | ||||||
|  |  | ||||||
|  |   /// set how long the controller should wait after opening a valve before closing the previous valve | ||||||
|  |   void set_valve_overlap(uint32_t valve_overlap); | ||||||
|  |  | ||||||
|  |   /// set how long the controller should wait to activate a valve after next_valve() or previous_valve() is called | ||||||
|  |   void set_manual_selection_delay(uint32_t manual_selection_delay); | ||||||
|  |  | ||||||
|  |   /// set how long the valve should remain on/open. run_duration is time in seconds | ||||||
|  |   void set_valve_run_duration(optional<size_t> valve_number, optional<uint32_t> run_duration); | ||||||
|  |  | ||||||
|  |   /// if auto_advance is true, controller will iterate through all enabled valves | ||||||
|  |   void set_auto_advance(bool auto_advance); | ||||||
|  |  | ||||||
|  |   /// set the number of times to repeat a full cycle | ||||||
|  |   void set_repeat(optional<uint32_t> repeat); | ||||||
|  |  | ||||||
|  |   /// if queue_enable is true, controller will iterate through valves in the queue | ||||||
|  |   void set_queue_enable(bool queue_enable); | ||||||
|  |  | ||||||
|  |   /// if reverse is true, controller will iterate through all enabled valves in reverse (descending) order | ||||||
|  |   void set_reverse(bool reverse); | ||||||
|  |  | ||||||
|  |   /// returns valve_number's run duration in seconds | ||||||
|  |   uint32_t valve_run_duration(size_t valve_number); | ||||||
|  |  | ||||||
|  |   /// returns valve_number's run duration (in seconds) adjusted by multiplier_ | ||||||
|  |   uint32_t valve_run_duration_adjusted(size_t valve_number); | ||||||
|  |  | ||||||
|  |   /// returns true if auto_advance is enabled | ||||||
|  |   bool auto_advance(); | ||||||
|  |  | ||||||
|  |   /// returns the current value of the multiplier | ||||||
|  |   float multiplier(); | ||||||
|  |  | ||||||
|  |   /// returns the number of times the controller is set to repeat cycles, if at all. check with 'has_value()' | ||||||
|  |   optional<uint32_t> repeat(); | ||||||
|  |  | ||||||
|  |   /// if a cycle is active, returns the number of times the controller has repeated the cycle. check with 'has_value()' | ||||||
|  |   optional<uint32_t> repeat_count(); | ||||||
|  |  | ||||||
|  |   /// returns true if the queue is enabled to run | ||||||
|  |   bool queue_enabled(); | ||||||
|  |  | ||||||
|  |   /// returns true if reverse is enabled | ||||||
|  |   bool reverse(); | ||||||
|  |  | ||||||
|  |   /// starts the controller from the first valve in the queue and disables auto_advance. | ||||||
|  |   /// if the queue is empty, does nothing. | ||||||
|  |   void start_from_queue(); | ||||||
|  |  | ||||||
|  |   /// starts a full cycle of all enabled valves and enables auto_advance. | ||||||
|  |   /// if no valves are enabled, all valves will be enabled. | ||||||
|  |   void start_full_cycle(); | ||||||
|  |  | ||||||
|  |   /// activates a single valve and disables auto_advance. | ||||||
|  |   void start_single_valve(optional<size_t> valve_number); | ||||||
|  |  | ||||||
|  |   /// adds a valve into the queue. queued valves have priority over valves to be run as a part of a full cycle. | ||||||
|  |   /// NOTE: queued valves will always run, regardless of auto-advance and/or valve enable switches. | ||||||
|  |   void queue_valve(optional<size_t> valve_number, optional<uint32_t> run_duration); | ||||||
|  |  | ||||||
|  |   /// clears/removes all valves from the queue | ||||||
|  |   void clear_queued_valves(); | ||||||
|  |  | ||||||
|  |   /// advances to the next valve (numerically) | ||||||
|  |   void next_valve(); | ||||||
|  |  | ||||||
|  |   /// advances to the previous valve (numerically) | ||||||
|  |   void previous_valve(); | ||||||
|  |  | ||||||
|  |   /// turns off all valves, effectively shutting down the system. | ||||||
|  |   void shutdown(bool clear_queue = false); | ||||||
|  |  | ||||||
|  |   /// same as shutdown(), but also stores active_valve() and time_remaining() allowing resume() to continue the cycle | ||||||
|  |   void pause(); | ||||||
|  |  | ||||||
|  |   /// resumes a cycle that was suspended using pause() | ||||||
|  |   void resume(); | ||||||
|  |  | ||||||
|  |   /// if a cycle was suspended using pause(), resumes it. otherwise calls start_full_cycle() | ||||||
|  |   void resume_or_start_full_cycle(); | ||||||
|  |  | ||||||
|  |   /// returns a pointer to a valve's name string object; returns nullptr if valve_number is invalid | ||||||
|  |   const char *valve_name(size_t valve_number); | ||||||
|  |  | ||||||
|  |   /// returns the number of the valve that is currently active, if any. check with 'has_value()' | ||||||
|  |   optional<size_t> active_valve(); | ||||||
|  |  | ||||||
|  |   /// returns the number of the valve that is paused, if any. check with 'has_value()' | ||||||
|  |   optional<size_t> paused_valve(); | ||||||
|  |  | ||||||
|  |   /// returns the number of the next valve in the queue, if any. check with 'has_value()' | ||||||
|  |   optional<size_t> queued_valve(); | ||||||
|  |  | ||||||
|  |   /// returns the number of the valve that is manually selected, if any. check with 'has_value()' | ||||||
|  |   ///  this is set by next_valve() and previous_valve() when manual_selection_delay_ > 0 | ||||||
|  |   optional<size_t> manual_valve(); | ||||||
|  |  | ||||||
|  |   /// returns the number of valves the controller is configured with | ||||||
|  |   size_t number_of_valves(); | ||||||
|  |  | ||||||
|  |   /// returns true if valve number is valid | ||||||
|  |   bool is_a_valid_valve(size_t valve_number); | ||||||
|  |  | ||||||
|  |   /// returns true if the pump the pointer points to is in use | ||||||
|  |   bool pump_in_use(SprinklerSwitch *pump_switch); | ||||||
|  |  | ||||||
|  |   /// switches on/off a pump "safely" by checking that the new state will not conflict with another controller | ||||||
|  |   void set_pump_state(SprinklerSwitch *pump_switch, bool state); | ||||||
|  |  | ||||||
|  |   /// returns the amount of time remaining in seconds for the active valve, if any. check with 'has_value()' | ||||||
|  |   optional<uint32_t> time_remaining(); | ||||||
|  |  | ||||||
|  |   /// returns a pointer to a valve's control switch object | ||||||
|  |   SprinklerControllerSwitch *control_switch(size_t valve_number); | ||||||
|  |  | ||||||
|  |   /// returns a pointer to a valve's enable switch object | ||||||
|  |   SprinklerControllerSwitch *enable_switch(size_t valve_number); | ||||||
|  |  | ||||||
|  |   /// returns a pointer to a valve's switch object | ||||||
|  |   SprinklerSwitch *valve_switch(size_t valve_number); | ||||||
|  |  | ||||||
|  |   /// returns a pointer to a valve's pump switch object | ||||||
|  |   SprinklerSwitch *valve_pump_switch(size_t valve_number); | ||||||
|  |  | ||||||
|  |   /// returns a pointer to a valve's pump switch object | ||||||
|  |   SprinklerSwitch *valve_pump_switch_by_pump_index(size_t pump_index); | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   uint32_t hash_base() override; | ||||||
|  |  | ||||||
|  |   /// returns true if valve number is enabled | ||||||
|  |   bool valve_is_enabled_(size_t valve_number); | ||||||
|  |  | ||||||
|  |   /// marks a valve's cycle as complete | ||||||
|  |   void mark_valve_cycle_complete_(size_t valve_number); | ||||||
|  |  | ||||||
|  |   /// returns true if valve's cycle is flagged as complete | ||||||
|  |   bool valve_cycle_complete_(size_t valve_number); | ||||||
|  |  | ||||||
|  |   /// returns the number of the next/previous valve in the vector | ||||||
|  |   size_t next_valve_number_(size_t first_valve); | ||||||
|  |   size_t previous_valve_number_(size_t first_valve); | ||||||
|  |  | ||||||
|  |   /// returns the number of the next valve that should be activated in a full cycle. | ||||||
|  |   ///  if no valve is next (cycle is complete), returns no value (check with 'has_value()') | ||||||
|  |   optional<size_t> next_valve_number_in_cycle_(optional<size_t> first_valve = nullopt); | ||||||
|  |  | ||||||
|  |   /// loads next_req_ with the next valve that should be activated, including its run duration. | ||||||
|  |   ///  if next_req_ already contains a request, nothing is done. after next_req_, | ||||||
|  |   ///  queued valves have priority, followed by enabled valves if auto-advance is enabled. | ||||||
|  |   ///  if no valve is next (for example, a full cycle is complete), next_req_ is reset via reset(). | ||||||
|  |   void load_next_valve_run_request_(optional<size_t> first_valve = nullopt); | ||||||
|  |  | ||||||
|  |   /// returns the number of the next/previous valve that should be activated. | ||||||
|  |   ///  if no valve is next (cycle is complete), returns no value (check with 'has_value()') | ||||||
|  |   optional<size_t> next_enabled_incomplete_valve_number_(optional<size_t> first_valve); | ||||||
|  |   optional<size_t> previous_enabled_incomplete_valve_number_(optional<size_t> first_valve); | ||||||
|  |  | ||||||
|  |   /// returns true if any valve is enabled | ||||||
|  |   bool any_valve_is_enabled_(); | ||||||
|  |  | ||||||
|  |   /// loads an available SprinklerValveOperator (valve_op_) based on req and starts it (switches it on). | ||||||
|  |   /// NOTE: if run_duration is zero, the valve's run_duration will be set based on the valve's configuration. | ||||||
|  |   void start_valve_(SprinklerValveRunRequest *req); | ||||||
|  |  | ||||||
|  |   /// turns off/closes all valves, including pump if include_pump is true | ||||||
|  |   void all_valves_off_(bool include_pump = false); | ||||||
|  |  | ||||||
|  |   /// prepares for a full cycle by verifying auto-advance is on as well as one or more valve enable switches. | ||||||
|  |   void prep_full_cycle_(); | ||||||
|  |  | ||||||
|  |   /// resets the cycle state for all valves | ||||||
|  |   void reset_cycle_states_(); | ||||||
|  |  | ||||||
|  |   /// resets resume state | ||||||
|  |   void reset_resume_(); | ||||||
|  |  | ||||||
|  |   /// make a request of the state machine | ||||||
|  |   void fsm_request_(size_t requested_valve, uint32_t requested_run_duration = 0); | ||||||
|  |  | ||||||
|  |   /// kicks the state machine to advance, starting it if it is not already active | ||||||
|  |   void fsm_kick_(); | ||||||
|  |  | ||||||
|  |   /// advance controller state, advancing to target_valve if provided | ||||||
|  |   void fsm_transition_(); | ||||||
|  |  | ||||||
|  |   /// starts up the system from IDLE state | ||||||
|  |   void fsm_transition_from_shutdown_(); | ||||||
|  |  | ||||||
|  |   /// transitions from ACTIVE state to ACTIVE (as in, next valve) or to a SHUTDOWN or IDLE state | ||||||
|  |   void fsm_transition_from_valve_run_(); | ||||||
|  |  | ||||||
|  |   /// starts up the system from IDLE state | ||||||
|  |   void fsm_transition_to_shutdown_(); | ||||||
|  |  | ||||||
|  |   /// return the current FSM state as a string | ||||||
|  |   std::string state_as_str_(SprinklerState state); | ||||||
|  |  | ||||||
|  |   /// Start/cancel/get status of valve timers | ||||||
|  |   void start_timer_(SprinklerTimerIndex timer_index); | ||||||
|  |   bool cancel_timer_(SprinklerTimerIndex timer_index); | ||||||
|  |   /// returns true if the specified timer is active/running | ||||||
|  |   bool timer_active_(SprinklerTimerIndex timer_index); | ||||||
|  |   /// time is converted to milliseconds (ms) for set_timeout() | ||||||
|  |   void set_timer_duration_(SprinklerTimerIndex timer_index, uint32_t time); | ||||||
|  |   /// returns time in milliseconds (ms) | ||||||
|  |   uint32_t timer_duration_(SprinklerTimerIndex timer_index); | ||||||
|  |   std::function<void()> timer_cbf_(SprinklerTimerIndex timer_index); | ||||||
|  |  | ||||||
|  |   /// callback functions for timers | ||||||
|  |   void valve_selection_callback_(); | ||||||
|  |   void sm_timer_callback_(); | ||||||
|  |   void pump_stop_delay_callback_(); | ||||||
|  |  | ||||||
|  |   /// Maximum allowed queue size | ||||||
|  |   const uint8_t max_queue_size_{100}; | ||||||
|  |  | ||||||
|  |   /// Pump should be off during valve_open_delay interval | ||||||
|  |   bool pump_switch_off_during_valve_open_delay_{false}; | ||||||
|  |  | ||||||
|  |   /// Sprinkler valve cycle should overlap | ||||||
|  |   bool valve_overlap_{false}; | ||||||
|  |  | ||||||
|  |   /// Pump start/stop delay interval types | ||||||
|  |   bool start_delay_is_valve_delay_{false}; | ||||||
|  |   bool stop_delay_is_valve_delay_{false}; | ||||||
|  |  | ||||||
|  |   /// Pump start/stop delay intervals | ||||||
|  |   uint32_t start_delay_{0}; | ||||||
|  |   uint32_t stop_delay_{0}; | ||||||
|  |  | ||||||
|  |   /// Sprinkler controller state | ||||||
|  |   SprinklerState state_{IDLE}; | ||||||
|  |  | ||||||
|  |   /// The valve run request that is currently active | ||||||
|  |   SprinklerValveRunRequest active_req_; | ||||||
|  |  | ||||||
|  |   /// The number of the manually selected valve currently selected | ||||||
|  |   optional<size_t> manual_valve_; | ||||||
|  |  | ||||||
|  |   /// The number of the valve to resume from (if paused) | ||||||
|  |   optional<size_t> paused_valve_; | ||||||
|  |  | ||||||
|  |   /// The next run request for the controller to consume after active_req_ is complete | ||||||
|  |   SprinklerValveRunRequest next_req_; | ||||||
|  |  | ||||||
|  |   /// Set the number of times to repeat a full cycle | ||||||
|  |   optional<uint32_t> target_repeats_; | ||||||
|  |  | ||||||
|  |   /// Set from time_remaining() when paused | ||||||
|  |   optional<uint32_t> resume_duration_; | ||||||
|  |  | ||||||
|  |   /// Manual switching delay | ||||||
|  |   optional<uint32_t> manual_selection_delay_; | ||||||
|  |  | ||||||
|  |   /// Valve switching delay | ||||||
|  |   optional<uint32_t> switching_delay_; | ||||||
|  |  | ||||||
|  |   /// Number of times the full cycle has been repeated | ||||||
|  |   uint32_t repeat_count_{0}; | ||||||
|  |  | ||||||
|  |   /// Sprinkler valve run time multiplier value | ||||||
|  |   float multiplier_{1.0}; | ||||||
|  |  | ||||||
|  |   /// Queue of valves to activate next, regardless of auto-advance | ||||||
|  |   std::vector<SprinklerQueueItem> queued_valves_; | ||||||
|  |  | ||||||
|  |   /// Sprinkler valve pump objects | ||||||
|  |   std::vector<SprinklerSwitch> pump_; | ||||||
|  |  | ||||||
|  |   /// Sprinkler valve objects | ||||||
|  |   std::vector<SprinklerValve> valve_; | ||||||
|  |  | ||||||
|  |   /// Sprinkler valve operator objects | ||||||
|  |   std::vector<SprinklerValveOperator> valve_op_{2}; | ||||||
|  |  | ||||||
|  |   /// Valve control timers | ||||||
|  |   std::vector<SprinklerTimer> timer_{ | ||||||
|  |       {this->name_ + "sm", false, 0, 0, std::bind(&Sprinkler::sm_timer_callback_, this)}, | ||||||
|  |       {this->name_ + "vs", false, 0, 0, std::bind(&Sprinkler::valve_selection_callback_, this)}}; | ||||||
|  |  | ||||||
|  |   /// Other Sprinkler instances we should be aware of (used to check if pumps are in use) | ||||||
|  |   std::vector<Sprinkler *> other_controllers_; | ||||||
|  |  | ||||||
|  |   /// Switches we'll present to the front end | ||||||
|  |   SprinklerControllerSwitch *auto_adv_sw_{nullptr}; | ||||||
|  |   SprinklerControllerSwitch *controller_sw_{nullptr}; | ||||||
|  |   SprinklerControllerSwitch *queue_enable_sw_{nullptr}; | ||||||
|  |   SprinklerControllerSwitch *reverse_sw_{nullptr}; | ||||||
|  |  | ||||||
|  |   std::unique_ptr<ShutdownAction<>> sprinkler_shutdown_action_; | ||||||
|  |   std::unique_ptr<ResumeOrStartAction<>> sprinkler_resumeorstart_action_; | ||||||
|  |  | ||||||
|  |   std::unique_ptr<Automation<>> sprinkler_turn_off_automation_; | ||||||
|  |   std::unique_ptr<Automation<>> sprinkler_turn_on_automation_; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | }  // namespace sprinkler | ||||||
|  | }  // namespace esphome | ||||||
| @@ -1128,6 +1128,49 @@ climate: | |||||||
|       ki: 0.0 |       ki: 0.0 | ||||||
|       kd: 0.0 |       kd: 0.0 | ||||||
|  |  | ||||||
|  | sprinkler: | ||||||
|  |   - id: yard_sprinkler_ctrlr | ||||||
|  |     main_switch: "Yard Sprinklers" | ||||||
|  |     auto_advance_switch: "Yard Sprinklers Auto Advance" | ||||||
|  |     reverse_switch: "Yard Sprinklers Reverse" | ||||||
|  |     pump_start_pump_delay: 2s | ||||||
|  |     pump_stop_valve_delay: 4s | ||||||
|  |     pump_switch_off_during_valve_open_delay: true | ||||||
|  |     valve_open_delay: 5s | ||||||
|  |     valves: | ||||||
|  |       - valve_switch: "Yard Valve 0" | ||||||
|  |         enable_switch: "Enable Yard Valve 0" | ||||||
|  |         pump_switch_id: gpio_switch1 | ||||||
|  |         run_duration: 10s | ||||||
|  |         valve_switch_id: gpio_switch2 | ||||||
|  |       - valve_switch: "Yard Valve 1" | ||||||
|  |         enable_switch: "Enable Yard Valve 1" | ||||||
|  |         pump_switch_id: gpio_switch1 | ||||||
|  |         run_duration: 10s | ||||||
|  |         valve_switch_id: gpio_switch2 | ||||||
|  |       - valve_switch: "Yard Valve 2" | ||||||
|  |         enable_switch: "Enable Yard Valve 2" | ||||||
|  |         pump_switch_id: gpio_switch1 | ||||||
|  |         run_duration: 10s | ||||||
|  |         valve_switch_id: gpio_switch2 | ||||||
|  |   - id: garden_sprinkler_ctrlr | ||||||
|  |     main_switch: "Garden Sprinklers" | ||||||
|  |     auto_advance_switch: "Garden Sprinklers Auto Advance" | ||||||
|  |     reverse_switch: "Garden Sprinklers Reverse" | ||||||
|  |     valve_overlap: 5s | ||||||
|  |     valves: | ||||||
|  |       - valve_switch: "Garden Valve 0" | ||||||
|  |         enable_switch: "Enable Garden Valve 0" | ||||||
|  |         pump_switch_id: gpio_switch1 | ||||||
|  |         run_duration: 10s | ||||||
|  |         valve_switch_id: gpio_switch2 | ||||||
|  |       - valve_switch: "Garden Valve 1" | ||||||
|  |         enable_switch: "Enable Garden Valve 1" | ||||||
|  |         pump_switch_id: gpio_switch1 | ||||||
|  |         run_duration: 10s | ||||||
|  |         valve_switch_id: gpio_switch2 | ||||||
|  |  | ||||||
|  |  | ||||||
| cover: | cover: | ||||||
|   - platform: endstop |   - platform: endstop | ||||||
|     name: Endstop Cover |     name: Endstop Cover | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user