def start_recipe_service(self, data, start_time=None): recipe_id = data.recipe_id if not recipe_id: return False, "No recipe id was specified" try: # Get the recipe document recipe = self.recipe_db[recipe_id] except Exception as e: return False, "\"{}\" does not reference a valid "\ "recipe".format(recipe_id) trace("recipe_handler: PUBLISHERS=%s", PUBLISHERS) trace("recipe_handler: recipe=%s", recipe) try: # Set the recipe document self.set_recipe(recipe, start_time) except RecipeRunningError: return (False, "There is already a recipe running. Please stop it " "before attempting to start a new one") return True, "Success"
def recover_any_previous_recipe(self): """ Attempt to resume any previous recipe that was started but not completed. """ # Get the recipe that has been started most recently start_view = self.env_data_db.view( "openag/by_variable", startkey=[self.environment, "desired", RECIPE_START.name], endkey=[self.environment, "desired", RECIPE_START.name, {}], group_level=3) if len(start_view) == 0: trace( "recover_any_previous_recipe: No previous recipe to recover.") return start_doc = start_view.rows[0].value trace("recover_any_previous_recipe: start_doc=%s", start_doc) # If a recipe has been ended more recently than the most recent time a # recipe was started, don't run the recipe end_view = self.env_data_db.view( "openag/by_variable", startkey=[self.environment, "desired", RECIPE_END.name], endkey=[self.environment, "desired", RECIPE_END.name, {}], group_level=3) if len(end_view): end_doc = end_view.rows[0].value trace("recover_any_previous_recipe: end_doc=%s", end_doc) if (end_doc["timestamp"] > start_doc["timestamp"]): trace( "recover_any_previous_recipe: RETURNING: '\ 'end_time=%s > start_time=%s", end_doc["timestamp"], start_doc["timestamp"]) return # Run the recipe trace("recover_any_previous_recipe: restarting recipe=%s at time=%s", start_doc["value"], start_doc["timestamp"]) self.start_recipe_service( StartRecipe._request_class(start_doc["value"]), start_doc["timestamp"])
def interpret_simple_recipe(recipe, start_time, now_time): """ Produces a tuple of ``(variable, value)`` pairs by building up a recipe state from walking through the recipe keyframes """ _id = recipe["_id"] operations = recipe["operations"] rospy.loginfo(operations) end_time_relative = operations[-1][0] trace("recipe_handler: interpret_simple_recipe end_time_relative=%s", end_time_relative) end_time = start_time + end_time_relative # If start time is at some point in the future beyond the threshold if start_time - now_time > THRESHOLD: raise ValueError("Recipes cannot be scheduled for the future") # If there are no recipe operations, immediately start and stop # The recipe. if not len(operations): return ( (RECIPE_START.name, _id), (RECIPE_END.name, _id), ) if now_time >= (end_time + THRESHOLD): return ((RECIPE_END.name, _id), ) if abs(now_time - start_time) < THRESHOLD: return ((RECIPE_START.name, _id), ) now_relative = (now_time - start_time) # Create a state object to accrue recipe setpoint values. state = {} # Build up state up until now_time (inclusive). trace("recipe_handler: interpret_simple_recipe now=%s", now_relative) for timestamp, variable, value in operations: if timestamp > now_relative: break state[variable] = value trace("recipe_handler: interpret_simple_recipe: %s %s %s", timestamp, variable, value) rospy.loginfo(state) return tuple((variable, value) for variable, value in state.iteritems())
def callback(data): recipe_handler.clear_recipe() trace("recipe_handler.Subscriber: clearing current recipe.")
rospy.logwarn("Invalid recipe format: '%s'", recipe_doc.get("format")) continue # Get recipe state and publish it setpoints = interpret_recipe(recipe_doc, start_time, now_time) for variable, value in setpoints: try: pub = PUBLISHERS[variable] except KeyError: msg = 'Recipe references invalid variable "{}"' rospy.logwarn(msg.format(variable)) continue # Publish any setpoints that we can trace("recipe_handler publish: %s, %s", variable, value) if variable == RECIPE_END.name: trace("recipe_handler publish: END!") # Write an env. data pt. for when we stopped this recipe. recipe_handler.save_recipe_dp(variable) elif variable == RECIPE_START.name: # Write an env. data pt. for when we started this recipe. recipe_handler.save_recipe_dp(variable) try: pub.publish(value) except ValueError: pass rate.sleep() # end of while loop in main