Previous
Flutter
The DoCommand
method is a flexible wrapper that you can use to send commands that have no corresponding built-in API method.
DoCommand
is part of every component and service API, though most models do not implement it.
In the majority of cases, you should use a more specific method for your component or service.
As the developer of a resource, you can implement DoCommand
in your module if you need to add custom commands to your resource.
As the user of a resource, you can only call DoCommand
if it is implemented in the model you are using.
Refer to the model’s documentation to see whether DoCommand
is implemented and how to use it.
DoCommand
takes a map of key-value pairs as input.
The contents of the map are entirely up to the developer of the resource.
DoCommand
also returns a map of key-value pairs, but many implementations return an empty map, or a map that confirms that the command was received.
There are many ways to implement DoCommand
in your module, with the following example being just one.
See More examples for more.
Imagine you have a robotic vacuum cleaner that has a docking sequence and can clean specific areas such as the kitchen and the living room.
You could write a module that implements the base API.
The base API includes methods like MoveStraight
to drive the vacuum cleaner around, and like all resource APIs, it includes a DoCommand
method.
In addition to the standard base methods, you could implement DoCommand
to trigger the docking and cleaning sequences:
async def do_command(
self,
command: Mapping[str, ValueTypes],
*,
timeout: Optional[float] = None,
**kwargs
) -> Mapping[str, ValueTypes]:
for name, value in command.items():
if name == "action":
action = value
if action == "dock":
await self.run_docking_sequence()
return {"status": "docked"}
elif isinstance(action, dict) and "clean_area" in action:
area = action["clean_area"]
if area in ["kitchen", "living_room"]:
await self.clean_area(area)
return {"status": f"cleaned {area}"}
else:
raise ValueError(f"Unknown area: {area}")
else:
raise ValueError(f"Unknown action: {action}")
else:
raise ValueError(f"Unknown command: {command}")
# TODO: Implement run_docking_sequence()
# TODO: Implement clean_area()
func (s *Vacuum) DoCommand(ctx context.Context, cmd map[string]interface{}) (map[string]interface{}, error) {
action, ok := cmd["action"]
if !ok {
return nil, fmt.Errorf("missing 'action' key in command")
}
switch action := action.(type) {
case string:
if action == "dock" {
if err := s.runDockingSequence(ctx); err != nil {
return nil, err
}
return map[string]interface{}{"status": "docked"}, nil
}
case map[string]interface{}:
if cleanArea, ok := action["clean_area"].(string); ok {
if cleanArea == "kitchen" || cleanArea == "living_room" {
if err := s.cleanArea(ctx, cleanArea); err != nil {
return nil, err
}
return map[string]interface{}{"status": fmt.Sprintf("cleaned %s", cleanArea)}, nil
}
return nil, fmt.Errorf("unknown area: %s", cleanArea)
}
}
return nil, fmt.Errorf("unknown action: %v", action)
}
// TODO: Implement runDockingSequence()
// TODO: Implement cleanArea()
Continuing with the vacuum cleaner example, you could use DoCommand
in your control code as follows:
# Dock the vacuum cleaner
await vacuum.do_command({"action": "dock"})
# Clean the kitchen
await vacuum.do_command({"action": {"clean_area": "kitchen"}})
// Dock the vacuum cleaner
_, err := vacuum.DoCommand(context.Background(), map[string]interface{}{
"action": "dock"})
if err != nil {
logger.Error(fmt.Errorf("failed to dock vacuum: %w", err))
}
// Clean the kitchen
_, err = vacuum.DoCommand(context.Background(), map[string]interface{}{
"action": map[string]interface{}{"clean_area": "kitchen"},
})
if err != nil {
logger.Error(fmt.Errorf("failed to clean area: %w", err))
}
You can use DoCommand
from the Viam app:
Navigate to your machine’s CONTROL tab.
Find your resource and expand the DO COMMAND section.
Enter a key and value in the text box using JSON syntax, for example
{
"action": { "clean_area": "kitchen" }
}
Click Execute.
For an example that implements DoCommand
in a generic API Python module, see Add control logic to your module.
For additional examples, look at the GitHub repositories of modules in the registry, especially modules that use the generic API.
Essentially all generic models implement DoCommand
(since it is the only method of the generic API), and various other models implement it as well.
Was this page helpful?
Glad to hear it! If you have any other feedback please let us know:
We're sorry about that. To help us improve, please tell us what we can do better:
Thank you!