A shell command provides an easy way to publish requests and inspect responses without rebuilding or reflashing. The template uses this pattern in several modules (for example power_shell.c, network_shell.c, cloud_shell.c) and you can reuse it for your own modules.
The recipe has three parts:
- A
<module>_shell.cfile that registers aSHELL_CMD_REGISTERroot command and a zbus listener that prints responses. - A Kconfig option (
CONFIG_APP_<MODULE>_SHELL, defaulty if SHELL) that gates the shell file so it is compiled only when the shell subsystem is enabled. - A
target_sources_ifdef()line in the module'sCMakeLists.txtso the shell file is built only when the option is set.
Apply the recipe to the dummy module as follows:
-
Create
app/src/modules/dummy/dummy_shell.c:#include <zephyr/shell/shell.h> #include <zephyr/zbus/zbus.h> #include <zephyr/kernel.h> #include <zephyr/logging/log.h> #include <errno.h> #include "app_common.h" #include "dummy.h" LOG_MODULE_DECLARE(dummy_module, CONFIG_APP_DUMMY_LOG_LEVEL); static bool sample_requested; static void dummy_shell_listener_callback(const struct zbus_channel *chan) { if (!sample_requested) { return; } const struct dummy_msg *msg = zbus_chan_const_msg(chan); if (msg->type == DUMMY_SAMPLE_RESPONSE) { LOG_INF("Dummy sample response: %d", msg->value); sample_requested = false; } } ZBUS_LISTENER_DEFINE(dummy_shell_listener, dummy_shell_listener_callback); ZBUS_CHAN_ADD_OBS(dummy_chan, dummy_shell_listener, 0); static int cmd_dummy_sample(const struct shell *sh, size_t argc, char **argv) { ARG_UNUSED(argc); ARG_UNUSED(argv); int err; struct dummy_msg msg = { .type = DUMMY_SAMPLE_REQUEST, }; err = zbus_chan_pub(&dummy_chan, &msg, PUB_TIMEOUT); if (err) { shell_print(sh, "Failed to send request: %d", err); return err; } sample_requested = true; shell_print(sh, "Requesting dummy sample..."); return 0; } SHELL_STATIC_SUBCMD_SET_CREATE( sub_cmds, SHELL_CMD(sample, NULL, "Request a dummy sample (publishes DUMMY_SAMPLE_REQUEST and prints the response)", cmd_dummy_sample), SHELL_SUBCMD_SET_END); SHELL_CMD_REGISTER(att_dummy, &sub_cmds, "Asset Tracker Template Dummy module commands", NULL);The listener checks a local
sample_requestedflag so it logs only the responses triggered by the most recent shell command, rather than everyDUMMY_SAMPLE_RESPONSEpublished on the channel. -
Add the Kconfig option to
app/src/modules/dummy/Kconfig.dummy, inside the existingif APP_DUMMYblock:config APP_DUMMY_SHELL bool "Dummy module shell commands" default y if SHELL help Enable shell commands for the dummy module. Adds the att_dummy sample command, which publishes a DUMMY_SAMPLE_REQUEST and logs the response. -
Append the conditional source to
app/src/modules/dummy/CMakeLists.txt:target_sources_ifdef(CONFIG_APP_DUMMY_SHELL app PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/dummy_shell.c)
To apply the same pattern to your own module, replace dummy with your module name in the file, Kconfig symbol, CMake option, channel, and message type. The root command (att_dummy here) is conventionally att_<module> so all template commands share a common prefix.