def step(self, value: Number, direction: str) -> StepperOutput: value = self.min_max.clip(value) max_ = self.min_max.max min_ = self.min_max.min step = (max_ - min_) / self.steps new_value = value + Stepper.apply_sign(step, direction) if self.min_max.is_between(new_value): return StepperOutput(round(new_value, 3), next_direction=direction) else: new_value = 2 * self.min_max.clip(new_value) - new_value return StepperOutput( round(new_value, 3), next_direction=Stepper.invert_direction(direction))
def step(self, value: Number, direction: str) -> StepperOutput: value = self.min_max.clip(value) # We add +1 to include `max` max_ = self.min_max.max min_ = self.min_max.min step = (max_ - min_) / self.steps new_value = (((value + Stepper.apply_sign(step, direction)) - min_) % (max_ - min_)) + min_ new_value = round(new_value, 3) return StepperOutput(new_value, next_direction=direction)
async def change_light_state( self, old: float, attribute: str, direction: str, stepper: Stepper, action_type: str, ) -> bool: """ This functions changes the state of the light depending on the previous value and attribute. It returns True when no more changes will need to be done. Otherwise, it returns False. """ attributes: Dict[str, Any] if attribute == LightController.ATTRIBUTE_XY_COLOR: index_color, _ = stepper.step(self.index_color, direction) self.index_color = int(index_color) xy_color = self.color_wheel[self.index_color] attributes = {attribute: xy_color} if action_type == "hold": attributes["transition"] = self.delay / 1000 await self.on(**attributes, light_on=True) # In case of xy_color mode it never finishes the loop, the hold loop # will only stop if the hold action is called when releasing the button. # I haven't experimented any problems with it, but a future implementation # would be to force the loop to stop after 4 or 5 loops as a safety measure. return False if self.check_smooth_power_on( attribute, direction, await self.get_entity_state(self.entity.name) ): await self.on_min(attribute, light_on=False) # # After smooth power on, the light should not brighten up. return True new_state_attribute, exceeded = stepper.step(old, direction) new_state_attribute = round(new_state_attribute, 3) attributes = {attribute: new_state_attribute} if action_type == "hold": attributes["transition"] = self.delay / 1000 await self.on(**attributes, light_on=True) self.value_attribute = new_state_attribute return exceeded
def get_stepper(self, attribute: str, steps: Number, mode: str) -> Stepper: previous_direction = Stepper.invert_direction(self.hold_toggle_direction_init) if attribute == LightController.ATTRIBUTE_XY_COLOR: return IndexLoopStepper(len(self.color_wheel), previous_direction) if mode not in STEPPER_MODES: raise ValueError( f"`{mode}` mode is not available. Options are: {list(STEPPER_MODES.keys())}" ) stepper_cls = STEPPER_MODES[mode] return stepper_cls( self.min_max_attributes[attribute], steps, previous_direction )
def step(self, value: Number, direction: str) -> StepperOutput: value = self.min_max.clip(value) sign = Stepper.sign(direction) max_ = self.min_max.max min_ = self.min_max.min step = (max_ - min_) / self.steps new_value = value + sign * step new_value = round(new_value, 3) if self.min_max.is_between(new_value): return StepperOutput(new_value, next_direction=direction) else: new_value = self.min_max.clip(new_value) return StepperOutput(new_value, next_direction=None)