diff --git a/docs/operate/get-started/other-hardware/_index.md b/docs/operate/get-started/other-hardware/_index.md
index 9a544f8bec..3cdf741bf2 100644
--- a/docs/operate/get-started/other-hardware/_index.md
+++ b/docs/operate/get-started/other-hardware/_index.md
@@ -1,17 +1,19 @@
---
+title: "Integrate other physical or virtual hardware"
linkTitle: "Integrate other hardware"
-title: "Integrate other hardware"
weight: 30
layout: "docs"
type: "docs"
no_list: true
-description: "Add support for more hardware to the Viam ecosystem."
+description: "Add support for more physical or virtual hardware to the Viam ecosystem."
---
-If your hardware is not [already supported](../supported-hardware/) by an existing {{< glossary_tooltip term_id="module" text="module" >}}, you can create a new module to add support for it.
+If your physical or virtual hardware is not [already supported](../supported-hardware/) by an existing {{< glossary_tooltip term_id="module" text="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.
+
{{% alert title="In this page" color="info" %}}
1. [Design your module](#design-your-module)
@@ -24,7 +26,6 @@ You can use built-in tools to manage versioning and deployment to machines as yo
- [Write a module for microcontrollers (to use alongside viam-micro-server)](./micro-module/)
- [Hello World guide to writing a module with Python or Go](./hello-world-module/)
-- [Write a module with C++](./cpp-module/)
- [Update and manage modules](./manage-modules/)
{{% /alert %}}
@@ -89,7 +90,7 @@ Authenticate your CLI session with Viam using one of the following options:
| Visibility | Choose `Private` to share only with your organization, or `Public` to share publicly with all organizations. If you are testing, choose `Private`. |
| Namespace/Organization ID | In the [Viam app](https://app.viam.com), navigate to your organization settings through the menu in upper right corner of the page. Find the **Public namespace** and copy that string. |
| Resource to add to the module (API) | The [component API](/appendix/apis/#component-apis) your module will implement. |
-| Model name | Name your component model based on what it supports, for example, if it supports a model of ultrasonic sensor called “XYZ Sensor 1234” you could call your model `XYZ_1234` or similar. |
+| Model name | Name your component model based on what it supports, for example, if it supports a model of ultrasonic sensor called “XYZ Sensor 1234” you could call your model `xyz_1234` or similar. Must be all-lowercase and use only alphanumeric characters (`a-z` and `0-9`), hyphens (`-`), and underscores (`_`). |
| Enable cloud build | You can select `No` if you will always build the module yourself before uploading it. If you select `Yes` and push the generated files (including the .github folder) and create a release of the format `vX.X.X`, the module will build and upload to the Viam registry and be available for all Viam-supported architectures without you needing to build for each architecture. |
| Register module | Select `Yes` unless you are creating a local-only module for testing purposes and do not intend to upload it. |
@@ -110,7 +111,7 @@ Edit the generated files to add your logic:
{{< tabs >}}
{{% tab name="Python" %}}
-1. Open /src/main.py.
+1. Open /src/main.py and add any necessary imports.
1. **Edit the `validate_config` function** to do the following:
- Check that the user has configured required attributes
@@ -264,6 +265,8 @@ if __name__ == "__main__":
{{< /expand >}}
+You can find more examples by looking at the source code GitHub repos linked from each module in the [Viam Registry](https://app.viam.com/registry).
+
5. **Add logging** messages as desired.
The following log levels are available for resource logs:
@@ -306,19 +309,188 @@ LOGGER.critical("critical info")
{{< /expand >}}
+6. Edit the generated requirements.txt file to include any packages that must be installed for the module to run.
+ Depending on your use case, you may not need to add anything here beyond `viam-sdk` which is auto-populated.
+
{{% /tab %}}
{{% tab name="Go" %}}
-1. Open `/models/.go` and add necessary imports.
+1. Open /models/your-model-name.go and add necessary imports.
+
+1. **Add any configurable attributes to the `Config` struct.**
+
+1. **Edit the `Validate` function** to do the following:
+
+ - Check that the user has configured required attributes
+ - Return any implicit dependencies
+
+
+ Explicit versus implicit dependencies
+
+ Some modular resources require that other {{< glossary_tooltip term_id="resource" text="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.
+ - Useful when dependencies are optional.
+ - 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.
+
+ - This is the preferred method when dependencies are required, because implicit dependencies make it more clear what needs to be configured, they eliminate the need for the same attribute to be configured twice, and they make debugging easier.
+
+
+
+1. **Edit the `Reconfigure` function** to do the following:
+
+ - Assign any default values as necessary to any optional attributes if the user hasn't configured them.
+
+1. **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](https://pkg.go.dev/go.viam.com/rdk/components).
+
+{{< expand "Example code for a camera module" >}}
+This example from [Hello World module](/operate/get-started/other-hardware/hello-world-module/) implements only one method of the camera API by returning a static image.
+
+```go {class="line-numbers linkable-line-numbers"}
+package models
+
+import (
+ "context"
+ "errors"
+ "io/ioutil"
+ "os"
+ "reflect"
+
+ "go.viam.com/rdk/components/camera"
+ "go.viam.com/rdk/gostream"
+ "go.viam.com/rdk/logging"
+ "go.viam.com/rdk/pointcloud"
+ "go.viam.com/rdk/resource"
+ "go.viam.com/utils/rpc"
+)
+
+var (
+ HelloCamera = resource.NewModel("jessamy", "hello-world", "hello-camera")
+ errUnimplemented = errors.New("unimplemented")
+ imagePath = ""
+)
+
+func init() {
+ resource.RegisterComponent(camera.API, HelloCamera,
+ resource.Registration[camera.Camera, *Config]{
+ Constructor: newHelloWorldHelloCamera,
+ },
+ )
+}
+
+type Config struct {
+ resource.AlwaysRebuild // Resource rebuilds instead of reconfiguring
+ ImagePath string `json:"image_path"`
+}
+
+func (cfg *Config) Validate(path string) ([]string, error) {
+ var deps []string
+ if cfg.ImagePath == "" {
+ return nil, resource.NewConfigValidationFieldRequiredError(path, "image_path")
+ }
+ if reflect.TypeOf(cfg.ImagePath).Kind() != reflect.String {
+ return nil, errors.New("image_path must be a string.")
+ }
+ imagePath = cfg.ImagePath
+ return deps, nil
+}
+
+type helloWorldHelloCamera struct {
+ name resource.Name
+
+ logger logging.Logger
+ cfg *Config
+
+ cancelCtx context.Context
+ cancelFunc func()
+}
+
+func newHelloWorldHelloCamera(ctx context.Context, deps resource.Dependencies, rawConf resource.Config, logger logging.Logger) (camera.Camera, error) {
+ conf, err := resource.NativeConfig[*Config](rawConf)
+ if err != nil {
+ return nil, err
+ }
+
+ cancelCtx, cancelFunc := context.WithCancel(context.Background())
+
+ s := &helloWorldHelloCamera{
+ name: rawConf.ResourceName(),
+ logger: logger,
+ cfg: conf,
+ cancelCtx: cancelCtx,
+ cancelFunc: cancelFunc,
+ }
+ return s, nil
+}
+
+func (s *helloWorldHelloCamera) Name() resource.Name {
+ return s.name
+}
+
+func (s *helloWorldHelloCamera) Reconfigure(ctx context.Context, deps resource.Dependencies, conf resource.Config) error {
+ return errUnimplemented
+}
+
+func (s *helloWorldHelloCamera) Image(ctx context.Context, mimeType string, extra map[string]interface{}) ([]byte, camera.ImageMetadata, error) {
+ imgFile, err := os.Open(imagePath)
+ if err != nil {
+ return nil, camera.ImageMetadata{}, errors.New("Error opening image.")
+ }
+ defer imgFile.Close()
+ imgByte, err := ioutil.ReadFile(imagePath)
+ return imgByte, camera.ImageMetadata{}, nil
+}
+
+func (s *helloWorldHelloCamera) NewClientFromConn(ctx context.Context, conn rpc.ClientConn, remoteName string, name resource.Name, logger logging.Logger) (camera.Camera, error) {
+ return nil, errors.New("not implemented")
+}
+
+func (s *helloWorldHelloCamera) Stream(ctx context.Context, errHandlers ...gostream.ErrorHandler) (gostream.VideoStream, error) {
+ return nil, errors.New("not implemented")
+}
+
+func (s *helloWorldHelloCamera) Images(ctx context.Context) ([]camera.NamedImage, resource.ResponseMetadata, error) {
+ return []camera.NamedImage{}, resource.ResponseMetadata{}, errors.New("not implemented")
+}
+
+func (s *helloWorldHelloCamera) NextPointCloud(ctx context.Context) (pointcloud.PointCloud, error) {
+ return nil, errors.New("not implemented")
+}
+
+func (s *helloWorldHelloCamera) Properties(ctx context.Context) (camera.Properties, error) {
+ return camera.Properties{}, errors.New("not implemented")
+}
+
+func (s *helloWorldHelloCamera) DoCommand(ctx context.Context, cmd map[string]interface{}) (map[string]interface{}, error) {
+ return map[string]interface{}{}, errors.New("not implemented")
+}
+
+func (s *helloWorldHelloCamera) Close(context.Context) error {
+ s.cancelFunc()
+ return nil
+}
+
+```
+
+{{< /expand >}}
+
+You can find more examples by looking at the source code GitHub repos linked from each module in the [Viam Registry](https://app.viam.com/registry).
{{% /tab %}}
{{< /tabs >}}
-5. Edit the generated requirements.txt file to include any packages that must be installed for the module to run.
- Depending on your use case, you may not need to add anything here beyond `viam-sdk` which is auto-populated.
-
## Test your module locally
+It's a good idea to test your module locally before uploading it to the [Viam Registry](https://app.viam.com/registry):
+
{{% expand "Prerequisite: A running machine connected to the Viam app." %}}
You can write a module without a machine, but to test your module you'll need a machine.
@@ -328,17 +500,40 @@ Make sure to physically connect your sensor to your machine's computer to prepar
{{% /expand%}}
-It's a good idea to test your module locally before uploading it to the [Viam Registry](https://app.viam.com/registry):
+1. {{< tabs >}}
+ {{% tab name="Python" %}}
+
+ Create a virtual Python environment with the necessary packages by running the setup file from within the hello-world directory:
+
+ ```sh {id="terminal-prompt" class="command-line" data-prompt="$"}
+ sh setup.sh
+ ```
+
+ This environment is where the local module will run.
+ `viam-server` does not need to run inside this environment.
+
+ {{% /tab %}}
+ {{% tab name="Go" %}}
+
+ From within the hello-world directory, compile your module into a single executable:
+
+ ```sh {class="command-line" data-prompt="$" data-output="5-10"}
+ make setup
+ make build
+ ```
+
+ {{% /tab %}}
+ {{< /tabs >}}
1. **Configure your local module** on a machine:
On your machine's **CONFIGURE** tab in the [Viam app](https://app.viam.com), 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, for example /Users/jessamy/my-sensor-module/run.sh.
+ Type in the _absolute_ path on your machine's filesystem to your module's executable file, for example /Users/jessamy/my-python-sensor-module/run.sh or /Users/artoo/my-go-module/main.go.
Click **Create**.
-2. **Configure the model** provided by your module:
+1. **Configure the model** provided by your module:
Click the **+** button again, this time selecting **Local module** and then **Local component**.
@@ -353,7 +548,7 @@ It's a good idea to test your module locally before uploading it to the [Viam Re
Configure any required attributes using proper JSON syntax.
-3. **Test the component**:
+1. **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.
@@ -502,29 +697,38 @@ Do not change the module_id
.
3. **Package and upload**:
- To package (for Python) and upload your module and make it available to configure on machines in your organization:
+ 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 meta.json file):
{{< tabs >}}
{{% tab name="Python" %}}
1. To package the module as an archive, run the following command from inside the module directory:
- ```sh {id="terminal-prompt" class="command-line" data-prompt="$"}
- tar -czf module.tar.gz run.sh setup.sh requirements.txt src
- ```
+ ```sh {id="terminal-prompt" class="command-line" data-prompt="$"}
+ 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.
+ 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 module.tar.gz.
+ This creates a tarball called module.tar.gz.
1. 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:
- ```sh {id="terminal-prompt" class="command-line" data-prompt="$"}
- viam module upload --version 1.0.0 --platform any module.tar.gz
- ```
+ ```sh {id="terminal-prompt" class="command-line" data-prompt="$"}
+ viam module upload --version 1.0.0 --platform any module.tar.gz
+ ```
- For details on platform support, see [Using the --platform argument](/cli/#using-the---platform-argument).
+ For details on platform support, see [Using the `--platform` argument](/cli/#using-the---platform-argument).
+
+ For details about versioning, see [Module versioning](/operate/get-started/supported-hardware/#module-versioning).
+
+ {{% alert title="Important" color="note" %}}
+ 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.
+ {{% /alert %}}
{{% /tab %}}
{{% tab name="Go" %}}
@@ -535,9 +739,24 @@ Do not change the module_id
.
viam module upload --version 1.0.0 --platform .
```
+ For details about versioning, see [Module versioning](/operate/get-started/supported-hardware/#module-versioning).
+
+ {{% alert title="Important" color="note" %}}
+ 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.
+ {{% /alert %}}
+
{{% /tab %}}
{{< /tabs >}}
Now, if you look at the [Viam Registry page](https://app.viam.com/registry) while logged into your account, you'll be able to find your module listed.
+
+## Add your new modular resource to your machines
+
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](/operate/get-started/supported-hardware/#configure-hardware-on-your-machine).
diff --git a/docs/operate/get-started/other-hardware/upload-module.md b/docs/operate/get-started/other-hardware/upload-module.md
deleted file mode 100644
index 5894f3b9e4..0000000000
--- a/docs/operate/get-started/other-hardware/upload-module.md
+++ /dev/null
@@ -1,307 +0,0 @@
----
-title: "Upload a module to the Viam Registry"
-linkTitle: "Upload a module"
-type: "docs"
-weight: 26
-images: ["/registry/module-puzzle-piece.svg"]
-icon: true
-tags: ["modular resources", "components", "services", "registry"]
-description: "Make your module available to others by uploading it to the modular resource registry."
-aliases:
- - /registry/upload/
- - /extend/modular-resources/upload/
- - /modular-resources/upload/
-languages: []
-viamresources: []
-platformarea: ["registry"]
-level: "Beginner"
-date: "2024-08-21"
-# updated: "" # When the tutorial was last entirely checked
-cost: "0"
----
-
-After [writing a module](/how-tos/create-module/), you can upload your module to the Viam Registry to:
-
-- share your module with other Viam users
-- deploy your module to a fleet of machines from a central interface
-
-You can choose to upload it to the Viam Registry as a _public module_ that is shared with other Viam users, or as a _private module_ that is shared only within your [organization](/cloud/organizations/).
-
-To upload your custom module to the [Viam Registry](https://app.viam.com/registry), either as a public or private module, use the Viam CLI commands `create` and `upload` following these instructions.
-
-{{% alert title="In this page" color="info" %}}
-
-- [Package and upload a module to the Viam Registry](#upload-a-module)
-
-{{% /alert %}}
-
-## Prerequisites
-
-{{% expand "A local module you've written and tested" %}}
-
-See [Create a Module](/how-tos/create-module/) or [Create a Sensor Module with Python](/how-tos/sensor-module/) for instructions.
-
-{{% /expand%}}
-
-## Upload a module
-
-{{< table >}}
-{{% tablestep %}}
-**1. Install the CLI**
-
-First, install the Viam CLI and authenticate to Viam, from the same machine that you intend to upload your module from.
-
-{{< readfile "/static/include/how-to/install-cli.md" >}}
-
-Authenticate your CLI session with Viam using one of the following options:
-
-{{< readfile "/static/include/how-to/auth-cli.md" >}}
-
-{{% /tablestep %}}
-{{% tablestep %}}
-**2. Generate a metadata file**
-
-Next, run the `viam module create` command to choose a custom module name and generate the required metadata for your module.
-By default, a new module is created as _private_, meaning that it is only accessible to members of your [organization](/cloud/organizations/), but you can choose to set the `visibility` of your module to _public_ to make it accessible to all Viam users.
-
-Select the private or public tab for instructions to upload your module with the respective `visibility` setting:
-
-{{< tabs >}}
-{{% tab name="Private" %}}
-
-Get the `org-id` for your {{< glossary_tooltip term_id="organization" text="organization" >}} from your organization's **Settings** page in the [Viam app](https://app.viam.com/) and run the following command from the same directory as your custom module to generate metadata for your module:
-
-```sh {id="terminal-prompt" class="command-line" data-prompt="$"}
-viam module create --name --org-id
-```
-
-If you later wish to make your module public, you can use the [`viam module update` command](/cli/#module).
-
-{{% /tab %}}
-{{% tab name="Public" %}}
-
-1. If you haven't already, [create a new namespace](/cloud/organizations/#create-a-namespace-for-your-organization) for your organization.
- If you have already created a namespace, you can find it on your organization's **Settings** page in the [Viam app](https://app.viam.com/), or by running the [`viam organizations list`](/cli/#organizations) command.
-
-2. To generate metadata for your module using your public namespace, run the following command from the same directory as your custom module:
-
- ```sh {id="terminal-prompt" class="command-line" data-prompt="$"}
- viam module create --name --public-namespace
- ```
-
-{{% /tab %}}
-{{< /tabs >}}
-
-This command creates a new `meta.json` metadata file in your current working directory, which serves as a template.
-
-{{% /tablestep %}}
-{{% tablestep %}}
-**3. Edit the metadata file**
-
-Edit the newly-created `meta.json` file, and provide the required configuration information for your custom module by filling in the following fields.
-
-
-
- Name |
- Type |
- Inclusion |
- Description |
-
-
- module_id |
- string |
- Required |
- The module ID, which includes either the module namespace or organization ID, followed by its name (pre-populated using the --name you provided in the viam module create command).
-
- Caution
-
- The module_id uniquely identifies your module.
- Do not change the module_id .
-
-
- |
-
-
-
- visibility |
- string |
- Required |
- Whether the module is accessible only to members of your organization (private ), or visible to all Viam users (public ). You can later make a private module public using the viam module update command. Once you make a module public, you can change it back to private if it is not configured on any machines outside of your organization.
Default: private |
-
-
- url |
- string |
- Optional |
- The URL of the GitHub repository containing the source code of the module. |
-
-
- description |
- string |
- Required |
- A description of your module and what it provides. |
-
-
- models |
- object |
- Required |
- A list of one or more {{< glossary_tooltip term_id="model" text="models" >}} provided by your custom module. You must provide at least one model, which consists of an api and model key pair. If you are publishing a public module ("visibility": "public" ), the namespace of your model must match the namespace of your organization. For more information, see naming your model. |
-
-
- entrypoint |
- string |
- Required |
- The name of the file that starts your module program. This can be a compiled executable, a script, or an invocation of another program. If you are providing your module as a single file to the upload command, provide the path to that single file. If you are providing a directory containing your module to the upload command, provide the path to the entry point file contained within that directory. |
-
-
- build |
- object |
- Optional |
- An object containing the command to run to build your module, as well as optional fields for the path to your dependency setup script, the target architectures to build for, and the path to your built module. Use this with the Viam CLI's build subcommand. |
-
-
-
-
-For example, the following represents the configuration of an example `my-module` public module in the `acme` namespace:
-
-{{< expand "Click to view example meta.json with build object" >}}
-
-```json {class="line-numbers linkable-line-numbers"}
-{
- "module_id": "acme:my-module",
- "visibility": "public",
- "url": "https://github.com//my-module",
- "description": "An example custom module.",
- "models": [
- {
- "api": "rdk:component:generic",
- "model": "acme:demo:my-model"
- }
- ],
- "build": {
- "path": "dist/archive.tar.gz", // optional - path to your built module
- "build": "./build.sh", // command that will build your module
- "arch": ["linux/amd64", "linux/arm64"] // architecture(s) to build for
- },
- "entrypoint": "dist/main" // path to executable
-}
-```
-
-{{< /expand >}}
-
-{{< expand "Click to view example meta.json without build object" >}}
-
-```json {class="line-numbers linkable-line-numbers"}
-{
- "module_id": "acme:my-module",
- "visibility": "public",
- "url": "https://github.com//my-module",
- "description": "An example custom module.",
- "models": [
- {
- "api": "rdk:component:generic",
- "model": "acme:demo:my-model"
- }
- ],
- "entrypoint": "my-module.sh" // path to executable
-}
-```
-
-{{< /expand >}}
-
-{{% alert title="Important" color="note" %}}
-
-In the example above, the model namespace is set to `acme` to match the owning organization's namespace.
-If the two namespaces do not match, the command will return an error.
-
-For more information, see [Name your new resource model](/how-tos/create-module/#name-your-new-resource-model).
-
-{{% /alert %}}
-
-See [`meta.json` file](/cli/#the-metajson-file) for more information.
-
-{{% /tablestep %}}
-{{% tablestep %}}
-**4. (For Python) Package module as an archive**
-
-For modules written in Python, you should package your module files as an archive first, before uploading.
-Other languages can proceed to the next step to upload their module directly.
-To package a module written in Python, run the following command from the same directory as your `meta.json` file:
-
-```sh {id="terminal-prompt" class="command-line" data-prompt="$"}
-tar -czvf dist/archive.tar.gz
-```
-
-where `` is the [packaged executable](/how-tos/create-module/#compile-or-package-your-module) that runs the module at the [entry point](/how-tos/create-module/#write-an-entry-point-main-program-file).
-If using PyInstaller, by default this would be `dist/main`.
-
-For a Python module built using the `venv` approach, the command might look like this:
-
-```sh {id="terminal-prompt" class="command-line" data-prompt="$"}
-tar -czf module.tar.gz run.sh requirements.txt src
-```
-
-Where `run.sh` is your [entrypoint file](/how-tos/create-module/#compile-or-package-your-module), `requirements.txt` is your [pip dependency list file](/how-tos/create-module/#compile-or-package-your-module), and `src` is the directory that contains the source code of your module.
-
-Supply the path to the resulting archive file in the next step.
-
-{{% /tablestep %}}
-{{% tablestep %}}
-**5. Upload your module**
-
-Run `viam module upload` to upload your custom module to the Viam Registry.
-Specify the path to the file, directory, or compressed archive (with `.tar.gz` or `.tgz` extension) that contains your custom module code:
-
-```sh {id="terminal-prompt" class="command-line" data-prompt="$"}
-viam module upload --version --platform --tags=
-```
-
-where:
-
-- `version`: provide a version for your custom module, using [semantic versioning](https://semver.org/) (example: `1.0.0`).
- You can later increment this value with subsequent `viam module upload` commands.
- See [Using the `--version` argument](/cli/#using-the---version-argument) for more information.
-- `platform`: provide the system architecture your custom module supports.
- You can only provide one `platform` argument at a time to the `viam module upload` command.
- See [Using the `--platform` argument](/cli/#using-the---platform-argument) for the full list of supported architectures.
-- `module-path`: provide the path to the file, directory, or compressed archive (with `.tar.gz` or `.tgz` extension) that contains your custom module code.
-- `tags`: provide a comma-separated list of platform tags that determine to which platforms this binary can be deployed. See [`viam module upload`](/cli/#module).
-
-{{% alert title="Important" color="note" %}}
-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.
-{{% /alert %}}
-
-For example:
-
-- To upload a module that is defined in a single file named `my-module-file` in a local `bin` directory:
-
- ```sh {id="terminal-prompt" class="command-line" data-prompt="$"}
- viam module upload --version 1.0.0 --platform linux/amd64 ./bin/my-module-file
- ```
-
-- To upload a module that includes multiple files, as well as a separate entry point file, all contained with a local `bin` directory:
-
- ```sh {id="terminal-prompt" class="command-line" data-prompt="$"}
- viam module upload --version 1.0.0 --platform linux/amd64 ./bin
- ```
-
-- To upload a module that has been compressed as an archive named `packaged-module.tar.gz`:
-
- ```sh {id="terminal-prompt" class="command-line" data-prompt="$"}
- viam module upload --version 1.0.0 --platform linux/amd64 packaged-module.tar.gz
- ```
-
-When you `upload` a module, the command performs basic [validation](/cli/#upload-validation) of your module to check for common errors.
-
-For more information, see the [`viam module` command](/cli/#module).
-
-{{% /tablestep %}}
-{{< /table >}}
-
-## Next steps
-
-Now that your module is available in the registry, you can configure the components or services it supports just as you would configure other resources: Go to the **CONFIGURE** tab of a machine, add a component or service (as applicable), and search for the name of your model.
-
-To update, delete, or change the privacy settings of a module you deployed, see [Manage Modules](/how-tos/manage-modules/).