Previous
Integrate supported hardware
If your physical or virtual hardware is not already supported by an existing module, you can create a new module to add support for it. You can keep the module private or share it with your organization or the public. You can use built-in tools to manage versioning and deployment to machines as you iterate on your module.
This page provides instructions for writing and uploading a module in Python or Go.
1. Write a test script (optional)
You can think of a module as a packaged wrapper around some script, that takes the functionality of the script and maps it to a standardized API for use within the Viam ecosystem. Start by finding or writing a test script to check that you can connect to and control your hardware from your computer, perhaps using the manufacturer’s API or other low-level code.
2. Choose an API
Decide exactly what functionality you want your module to provide in terms of inputs and outputs. With this in mind, look through the component APIs and choose one that fits your use case.
For example, if you just need to get readings or other data and don’t need any other endpoints, you could use the sensor API, which contains only the GetReadings
method (as well as the methods that all Viam resources implement: Reconfigure
, DoCommand
, GetResourceName
, and Close
).
You do not need to fully implement all the methods of an API.
For example, if you want to use the camera API because you want to return images, but your camera does not get point cloud data, you can implement the GetImage
method but for the GetPointCloud
method you can return nil and an “unimplemented” error or similar, depending on the method and the language you use to write your module.
If you need a method that is not in your chosen API, you can use the flexible DoCommand
(which is built into all component APIs) to create custom commands.
3. Decide on configuration attributes and dependencies
Make a list of required and optional attributes for users to configure when adding your module to a machine.
For example, you can require users to configure a path from which to access data, or a pin to which a device is wired, and you could allow them to optionally change a frequency from some default.
You’ll need to add these attributes to the Validate
and Reconfigure
functions when you write the module.
The easiest way to generate the files for your module is to use the Viam CLI:
Install the Viam CLI and authenticate to Viam, from the same machine that you intend to upload your module from.
Run the module generate
command in your terminal:
viam module generate
Follow the prompts.
The generator will create a folder containing stub files for your modular sensor component. In the next section, you’ll customize some of the generated files to support your sensor.
If you have multiple modular components that are related to or even dependent upon each other, you can opt to put them all into one module. For an example of how this is done, see Create a Hello World module.
Edit the generated files to add your logic:
Open
Edit the validate_config
function to do the following:
Check that the user has configured required attributes
Return any implicit dependencies
Some modular resources require that other resources start up first. For example, a mobile robotic base might need its motors to instantiate before the overall base module instantiates. If your use case requires that things initialize in a specific order, you have two options:
Explicit dependencies: Require that a user list the names of all resources that must start before a given component in the depends_on
field of the component’s configuration.
Implicit dependencies: Instead of explicitly using the depends_on
field, require users to configure a named attribute (for example "left-motor": "motor1"
), and write your module with that attribute as a dependency.
Note that most named attributes are not dependencies; you need to specify a resource as not only an attribute but also a dependency for it to be initialized first.
See code examples below.
Edit the reconfigure
function to do the following:
Edit the methods you want to implement:
For each method you want to implement, replace the body of the method with the relevant logic from your test script. Make sure you return the correct type in accordance with the function’s return signature. You can find details about the return types at python.viam.dev.
You can find more examples by looking at the source code GitHub repos linked from each module in the Viam Registry.
Add logging messages as desired. The following log severity levels are available for resource logs:
# Within some method, log information:
self.logger.debug("debug info")
self.logger.info("info")
self.logger.warn("warning info")
self.logger.error("error info")
self.logger.exception("error info", exc_info=True)
self.logger.critical("critical info")
Resource-level logs are recommended instead of global logs for modular resources, because they make it easier to determine which component or service an error is coming from. Resource-level error logs appear in the ERROR LOGS section of each resource’s configuration card in the app.
In order to see resource-level debug logs when using your modular resource, you’ll either need to run viam-server
with the -debug
option or configure your machine or individual resource to display debug logs.
viam-sdk
which is auto-populated.Open
Add any configurable attributes to the Config
struct.
Edit the Validate
function to do the following:
Check that the user has configured required attributes
Return any implicit dependencies
Some modular resources require that other resources start up first. For example, a mobile robotic base might need its motors to instantiate before the overall base module instantiates. If your use case requires that things initialize in a specific order, you have two options:
Explicit dependencies: Require that a user list the names of all resources that must start before a given component in the depends_on
field of the component’s configuration.
Implicit dependencies: Instead of explicitly using the depends_on
field, require users to configure a named attribute (for example "left-motor": "motor1"
), and write your module with that attribute as a dependency.
Note that most named attributes are not dependencies; you need to specify a resource as not only an attribute but also a dependency for it to be initialized first.
See code examples below.
Edit the Reconfigure
function to do the following:
Edit the methods you want to implement:
For each method you want to implement, replace the body of the method with the relevant logic from your test script. Make sure you return the correct type in accordance with the function’s return signature. You can find details about the return types at go.viam.com/rdk/components.
You can find more examples by looking at the source code GitHub repos linked from each module in the Viam Registry.
Add logging messages as desired.
You can add log messages with various levels of severity:
fn (c *component) someFunction(ctx context.Context, a int) {
// Log with severity info:
c.logger.CInfof(ctx, "performing some function with a=%v", a)
// Log with severity debug (using value wrapping):
c.logger.CDebugw(ctx, "performing some function", "a" ,a)
// Log with severity warn:
c.logger.CWarnw(ctx, "encountered warning for component", "name", c.Name())
// Log with severity error without a parameter:
c.logger.CError(ctx, "encountered an error")
}
In order to see debug logs when using your modular resource, you’ll need to run viam-server
with the -debug
option.
It’s a good idea to test your module locally before uploading it to the Viam Registry:
1. Prepare to run your module
To follow these PyInstaller packaging steps, you must have enabled cloud build when moving through the module generator prompts.
If you did not, you will need to manually create a
From within the
sh setup.sh
sh build.sh
This environment is where the local module will run.
viam-server
does not need to run inside this environment.
Create a virtual Python environment with the necessary packages by running the setup file from within the
sh setup.sh
This environment is where the local module will run.
viam-server
does not need to run inside this environment.
From within the
make setup
make build
2. Configure your local module on a machine
On your machine’s CONFIGURE tab in the Viam app, click the + (create) icon in the left-hand menu. Select Local module, then Local module.
Type in the absolute path on your machine’s filesystem to your module’s executable file:
Enter the absolute path to the
Enter the absolute path to the
Enter the absolute path to the
Click Create.
3. Configure the model provided by your module
Click the + button again, this time selecting Local module and then Local component.
Select or enter the model namespace triplet, for example jessamy:weather:meteo-PM
.
You can find the triplet in the model
field of your
Select the Type corresponding to the API you implemented.
Enter a Name such as my-cool-component
.
Click Create.
Configure any required attributes using proper JSON syntax.
4. Test the component
Click the TEST bar at the bottom of your modular component configuration, and check whether it works as expected. For example, if you created a sensor component, check whether readings are displayed.
5. Iterate
If your component works, you’re almost ready to share your module by uploading it to the registry. If not, you have some debugging to do.
Each time you make changes to your local module, you need to rebuild the module and then restart its instance on your machine. Run the following command to rebuild it:
viam module build local
Then restart it in your machine’s CONFIGURE tab in the Viam app. In upper right corner of the module’s card, click the three dot (…) icon, then click Restart.
For help, don’t hesitate to reach out on the Community Discord.
Once you are done testing locally, you can upload your module to the Viam Registry and make it available either to all machines in your organization, or to the general public.
1. Create a README (optional)
It’s quite helpful to create a README to document what your module does and how to use it, especially if you plan to share your module with others.
2. Create a GitHub repo (optional)
Create a GitHub repository with all the source code and the README for your module.
Add the link to that repo as the url
in the
3. Edit the meta.json file
Make any necessary edits to the meta.json
file.
Click below for information about the available fields.
4. Package and upload
To package (for Python) and upload your module and make it available to configure on machines in your organization (or in any organization, depending on how you set visibility
in the
The recommended approach for Python is to use PyInstaller to compile your module into a packaged executable: a standalone file containing your program, the Python interpreter, and all of its dependencies. When packaged in this fashion, you can run the resulting executable on your desired target platform or platforms without needing to install additional software or manage dependencies manually.
To follow these PyInstaller packaging steps, you must have enabled cloud build when moving through the module generator prompts.
The
Run the viam module upload
CLI command to upload the module to the registry, replacing any
with one or more of linux/any
or darwin/any
if your module requires Linux OS-level support or macOS OS-level support, respectively.
If your module does not require OS-level support (such as platform-specific dependencies), you can run the following command exactly:
viam module upload --version 1.0.0 --platform any module.tar.gz
For details on platform support, see Using the --platform
argument.
For details about versioning, see Module versioning.
The viam module upload
command only supports one platform
argument at a time.
If you would like to upload your module with support for multiple platforms, you must run a separate viam module upload
command for each platform.
Use the same version number when running multiple upload
commands of the same module code if only the platform
support differs.
The Viam Registry page for your module displays the platforms your module supports for each version you have uploaded.
We recommend you use PyInstaller with the build-action
GitHub action which provides a simple cross-platform build setup for multiple platforms: x86 and Arm Linux distributions, and MacOS.
See Update an existing module using a GitHub action for more information.
PyInstaller does not support relative imports in entrypoints (imports starting with .
).
If you get "ImportError: attempted relative import with no known parent package"
, set up a stub entrypoint as described on GitHub.
In addition, PyInstaller does not support cross-compiling: you must compile your module on the target architecture you wish to support.
For example, you cannot run a module on a Linux arm64
system if you compiled it using PyInstaller on a Linux amd64
system.
Viam makes this easy to manage by providing a build system for modules.
Follow these instructions to automatically build for each system your module can support using Viam’s CLI.
You can use the following package and upload method if you opted not to enable cloud build when you ran viam module generate
.
To package the module as an archive, run the following command from inside the module directory:
tar -czf module.tar.gz run.sh setup.sh requirements.txt src
where run.sh
is your entrypoint file, requirements.txt
is your pip dependency list file, and src
is the directory that contains the source code of your module.
This creates a tarball called
Run the viam module upload
CLI command to upload the module to the registry, replacing any
with one or more of linux/any
or darwin/any
if your module requires Linux OS-level support or macOS OS-level support, respectively.
If your module does not require OS-level support (such as platform-specific dependencies), you can run the following command exactly:
viam module upload --version 1.0.0 --platform any module.tar.gz
For details on platform support, see Using the --platform
argument.
For details about versioning, see Module versioning.
The viam module upload
command only supports one platform
argument at a time.
If you would like to upload your module with support for multiple platforms, you must run a separate viam module upload
command for each platform.
Use the same version number when running multiple upload
commands of the same module code if only the platform
support differs.
The Viam Registry page for your module displays the platforms your module supports for each version you have uploaded.
From within your module’s directory, run the viam module upload
CLI command to upload the module to the registry, replacing <platform>
with linux/amd64
, linux/arm64
, or one or more other platforms depending on what your module requires.
viam module upload --version 1.0.0 --platform <platform> .
For details about versioning, see Module versioning.
The viam module upload
command only supports one platform
argument at a time.
If you would like to upload your module with support for multiple platforms, you must run a separate viam module upload
command for each platform.
Use the same version number when running multiple upload
commands of the same module code if only the platform
support differs.
The Viam Registry page for your module displays the platforms your module supports for each version you have uploaded.
Now, if you look at the Viam Registry page while logged into your account, you’ll be able to find your module listed.
Now that your module is in the registry, you can configure the component you added on your machines just as you would configure other components and services; there’s no more need for local module configuration. The local module configuration is primarily for testing purposes.
Click the + button on your machine’s CONFIGURE tab and search for your model. For more details, see Configure hardware on your machine.
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!