From 5ad55fbf1e8d37d3e079e1e8019a12381698a1f2 Mon Sep 17 00:00:00 2001 From: Naomi Pentrel <5212232+npentrel@users.noreply.github.com> Date: Tue, 27 May 2025 13:08:46 +0200 Subject: [PATCH 1/4] Update Air Quality tutorial --- docs/tutorials/control/air-quality-fleet.md | 928 +++++++++++++------- 1 file changed, 588 insertions(+), 340 deletions(-) diff --git a/docs/tutorials/control/air-quality-fleet.md b/docs/tutorials/control/air-quality-fleet.md index 0bea49f7c6..dba7617363 100644 --- a/docs/tutorials/control/air-quality-fleet.md +++ b/docs/tutorials/control/air-quality-fleet.md @@ -20,131 +20,135 @@ cost: 200 # 2. The reader can identify when to use fragments and evaluate when it is worth using fragments. # The reader can create their own fragments for their projects and knows what to include and exclude from them. # 3. The reader recognizes how permissions enable the management of data for a business across multiple customers while providing each customer access to their own data. +# 4. The reader can deploy custom frond ends that end users can use to operate their machines. --- -In this tutorial you will use a fleet of devices to collect air quality data from different places and display the most recent readings from each device in a custom viewing dashboard. +In this tutorial you will learn how to set up a fleet of devices for yourself or third parties to collect air quality data. +You will then create a web app that shows the most recent reading for any device a user has access to. {{< alert title="Learning Goals" color="info" >}} By completing this project, you will learn to: -- Configure a fleet of identical machines +- Configure a fleet of machines - Organize your fleet using {{< glossary_tooltip term_id="location" text="locations" >}} - Collect and sync data from multiple machines -- Use the Viam TypeScript SDK to query sensor data and create a custom dashboard -- Use API keys to provide access to different groups of machines +- Use the Viam TypeScript SDK to query sensor data +- Create a custom dashboard that you and third parties can use to view data for their respective machines. {{< /alert >}} -![Air quality dashboard in a web browser with PM2.5 readings from three different sensor machines displayed.](/tutorials/air-quality-fleet/three-sensor-dash-wide.png) +{{}} ## Requirements -You can complete this tutorial using any number of air quality sensing machines. +You can create one or more machines to measure air quality. +For each machine, you need the following hardware: -For each machine, you will need the following hardware: - -- [SDS011 Nova PM sensor](https://www.amazon.com/SDS011-Quality-Detection-Conditioning-Monitor/dp/B07FSDMRR5) +- one or more [SDS011 Nova PM sensors](https://www.amazon.com/SDS011-Quality-Detection-Conditioning-Monitor/dp/B07FSDMRR5) - If you choose to use a different air quality sensor, you may need to [create your own module](/operate/get-started/other-hardware/) implementing the [sensor API](/operate/reference/components/sensor/#api) for your specific hardware. - A single-board computer (SBC) [capable of running `viam-server`](https://docs.viam.com/installation/) - An appropriate power supply -Make sure all of your sensors are wired to your SBC before starting this tutorial. +## Set up one device for development -## Decide how you will organize your fleet +In this section we'll set up one air sensing machine as our development device. -Before you start connecting your devices to the Viam app, you'll need to decide how you want to group your devices. +{{< table >}} +{{% tablestep number=1 %}} -In the Viam app, {{< glossary_tooltip term_id="machine" text="machines" >}} are grouped into _locations_, and locations are grouped into _organizations_: +Navigate to the [Viam app](https://app.viam.com) in a web browser. +Create an account and log in. -- Each location can represent either a physical location or some other conceptual grouping. -- An organization is the highest level grouping, and often contains all the locations (and machines) of an entire company. +{{% /tablestep %}} +{{% tablestep number=2 %}} -These groupings allow you to manage permissions; you can grant a user access to an individual machine, to all the machines in a location, or to everything in an entire organization. -You choose how to group your machines. +Click the dropdown in the upper-right corner of the **FLEET** page and use the **+** button to create a new organization for your air quality machine company. +Name the organization and click **Create**. -{{}} +{{% /tablestep %}} +{{% tablestep number=3 %}} -
+Click **FLEET** in the upper-left corner of the page and click **LOCATIONS**. +A new location called `First Location` is automatically generated for you. +Use the **...** menu next to edit the location name to `Development`, then click **Save**. -For more information, see [Fleet Management](/manage/reference/organize/). +{{% /tablestep %}} +{{% tablestep number=4 %}} -### Example +Connect a PM sensor to a USB port on the machine's SBC. +Then connect your device to power. -Imagine you create an air quality monitoring company called Pollution Monitoring Made Simple. -Anyone can sign up and order one of your sensing machines. -When a new customer signs up, you assemble a new machine with a sensor, SBC, and power supply. +If the computer does not already have a Viam-compatible operating system installed, follow the [operating system setup section of the Quickstart guide](/operate/get-started/setup/) to install a compatible operating system. +You _do not_ need to follow the "Install `viam-server`" section; you will do that in the next step! -Before shipping the sensor machine to your new client, you connect the machine to the Viam app and configure it. -To manage all your company's air quality sensing machines together, you create one organization called Pollution Monitoring Made Simple. -Inside that organization, you create a location for each customer. -You have some individual customers, for example Antonia, who have a sensor machine in their home, or perhaps one inside and one outside. -You have other customers who are businesses, for example RobotsRUs, who have two offices, one in New York and one in Oregon, with multiple sensor machines in each. -RobotsRUs wants to separate their sensor data by physical location, so you create a location for RobotsRUs and then create sub-locations to group their New York sensor machines and their Oregon machines. +Enable serial communication so that the SBC can communicate with the air quality sensor. +For example, if you are using a Raspberry Pi, SSH to it and [enable serial communication in `raspi-config`](/operate/reference/prepare/rpi-setup/#enable-communication-protocols). -When you grant Antonia access to her location, she will be able to view data from the air sensors at her home. -When you grant RobotsRUs access to their location, they will be able to view data from all of their sub-locations, or they can choose to spin up a dashboard showing data from only one sub-location at a time. -You, as the organization owner, will be able to manage any necessary configuration changes for all air sensing machines in all locations created within the Pollution Monitoring Made Simple organization. +{{% /tablestep %}} +{{% tablestep number=5 %}} -{{}} +Add a new [_{{< glossary_tooltip term_id="machine" text="machine" >}}_](/operate/get-started/basics/#what-is-a-machine) using the button in the top right corner of the **LOCATIONS** tab in the app. +Follow the **Set up your machine part** instructions to install `viam-server` on the machine and connect it to the Viam app. -### Organize your fleet +When your machine shows as connected, continue to the next step. -For this tutorial, we will walk through how to set up your fleet based on the example above. -You can choose to manage your fleet of machines differently based on what makes sense for your use case; if you're only configuring one or two sensors for personal use, feel free to add all your machines to one location and skip to the [next section](#connect-your-machines-to-the-viam-app). +{{% /tablestep %}} +{{% tablestep number=6 %}} -1. Navigate to the [Viam app](https://app.viam.com) in a web browser. - Create an account and log in. -1. Click the dropdown in the upper-right corner of the **FLEET** page and use the **+** button to create a new organization for your air quality machine company. - Name the organization and click **Create**. -1. Click **FLEET** in the upper-left corner of the page and click **LOCATIONS**. - A new location called `First Location` is automatically generated for you. - Rename it so you can use it for Antonia's machines: +Navigate to the **CONFIGURE** tab of the machine, click the **+** button and select **Component or service**. +Click **sensor**, then search for `sds011` and add the **sds001:v1** {{< glossary_tooltip term_id="module" text="module" >}}. +Name the sensor `PM_sensor` and click **Create**. - Use the **...** menu next to edit the location name to `Antonia's Home`, then click **Save**. +{{}} -1. Now, create a separate location for RobotsRUs: +{{% /tablestep %}} +{{% tablestep number=7 %}} - On the left side of the **LOCATIONS** page, click the **Add location** button. - Type in `RobotsRUs` and click **Add**. +In the newly created **PM_sensor** card, replace the contents of the attributes box (the empty curly braces `{}`) with the following: -1. Add sub-locations to the RobotsRUs location to group the machines at each of their offices: +```json {class="line-numbers linkable-line-numbers"} +{ + "usb_interface": "" +} +``` - Add a new location called `Oregon Office` using the same **Add location** button. - Then, find the **New parent location** dropdown on the Oregon Office page. - Select **RobotsRUs** and click **Change**. +{{% /tablestep %}} +{{% tablestep number=8 %}} - Repeat to add the New York office: Add a new location called `New York Office`, then change its parent location to **RobotsRUs**. +To figure out which port your sensor is connected to on your board, SSH to your board and run the following command: - {{}} +```sh{class="command-line" data-prompt="$"} +ls /dev/serial/by-id +``` - In the next section, you'll add machines to the locations. +This should output a list of one or more USB devices attached to your board, for example `usb-1a86_USB_Serial-if00-port0`. +If the air quality sensor is the only device plugged into your board, you can be confident that the only device listed is the correct one. +If you have multiple devices plugged into different USB ports, you may need to choose one path and test it, or unplug something, to figure out which path to use. -## Connect your machines to the Viam app +Now that you have found the identifier, put the full path to the device into your config, for example: -With your organizational structure in place, let's add some machines: +```json {class="line-numbers linkable-line-numbers"} +{ + "usb_interface": "/dev/serial/by-id/usb-1a86_USB_Serial-if00-port0" +} +``` -1. Connect your first single-board computer to power. - For this tutorial, we'll treat this as the machine for our first customer, Antonia. - If the computer does not already have a Viam-compatible operating system installed, follow the [operating system setup section of the Quickstart guide](/operate/get-started/setup/) to install a compatible operating system. - You _do not_ need to follow the "Install `viam-server`" section; you will do that in the next step! +{{% /tablestep %}} +{{% tablestep number=9 %}} -1. Enable serial communication so that the SBC can communicate with the air quality sensor. - For example, if you are using a Raspberry Pi, SSH to it and [enable serial communication in `raspi-config`](/operate/reference/prepare/rpi-setup/#enable-communication-protocols). +Save the config. -1. Click **Antonia's Home** in the left navigation menu to navigate to that location's page. - In the **New machine** field near the top-right corner of the screen, type in a name for the machine, such as `Home Air Quality Sensor`, and click **Add machine**. +{{}} -1. You'll be taken to the machine details page and prompted to set up your machine part. - Click **View setup instructions**. - You can find these instructions later if you need them by clicking the part status indicator (which currently reads **Awaiting setup**). +{{% /tablestep %}} +{{% tablestep number=10 %}} -1. Follow the **Set up your machine part** instructions to install `viam-server` on the machine and connect it to the Viam app. - `viam-server` is the binary that runs on the single-board computer (SBC), providing functionality including sensor data collection and connection to the Viam app. +On your sensor configuration panel, click on the **TEST** panel to check that you are getting readings from your sensor. - The setup page will indicate when the machine is successfully connected. +{{}} -1. If Antonia has more than one air sensing machine, add a new machine to her location and set it up in the same way. +If you do not see readings, check the **LOGS** tab for errors, double-check that serial communication is enabled on the single board computer, and check that the `usb_interface` path is correctly specified (click below). This is how you set up one machine. If you are following along for the RobotsRUs business from our example, create additional machines in each sub-location, that is, in the `Oregon Office` location and in the `New York Office` location. @@ -343,302 +347,338 @@ If not, you can use [fragment overwrite](/manage/fleet/reuse-configuration/#modi {{< /expand >}} -## Test data sync +{{% /tablestep %}} +{{% tablestep number=11 %}} + +Click **+** and add the **data management** service. +Toggle **Syncing** to the on position and set the sync interval to `0.05` minutes so that data syncs to the cloud every 3 seconds. -Next, check that data is being synced from your sensors to the cloud: +Add a tag to all your data so that you can query data from all your air quality sensors more easily in later steps. +In the **Tags** field, type `air-quality` and click **+ Tag: air-quality** when it appears to create a new tag. +This tag will now automatically be applied to all data collected by this data manager. -1. Open your [**DATA** page](https://app.viam.com/data). -2. Click the **Sensors** tab within the data page. -3. If you have sensor data coming from machines unrelated to this project, use the filters on the left side of the page to view data from only your air quality sensors. - Click the **Tags** dropdown and select the `air-quality` tag you applied to your data. - You can also use these filters to show the data from one of your air quality sensors at a time by typing a machine name into the **Machine name** box and clicking **Apply** in the lower-left corner. +{{% /tablestep %}} +{{% tablestep number=12 %}} - ![The sensor readings that have synced to the DATA page.](/tutorials/air-quality-fleet/synced-data.png) +On the **PM_sensor** panel, click **Add method** to add data capture. -Once you've confirmed that data is being collected and synced correctly, you're ready to start building a dashboard to display the data. -If you'd like to graph your data using a Grafana dashboard, try our [Visualize Data with Grafana tutorial](/tutorials/services/visualize-data-grafana/). -If you'd like to create your own customizable dashboard using the Viam TypeScript, continue with this tutorial. +- **Type** :**Readings**. +- **Frequency**: `0.1` -## Code your custom TypeScript dashboard +Save the config. + +You can check that your sensor data is being synced by clicking on the **...** menu and clicking **View captured data**. + +{{% /tablestep %}} +{{< /table >}} + +Congratulations, if you made it this far, you now have a functional air sensing machine. +Let's create a dashboard for its measurements next. + +## Create a dashboard The [Viam TypeScript SDK](https://ts.viam.dev/) allows you to build custom web interfaces to interact with your machines. For this project, you'll use it to build a page that displays air quality sensor data for a given location. -You'll host the website locally on your personal computer, and view the interface in a web browser on that computer. +You'll host the website on Viam Apps. -As you'll find out in the [authentication step](#authenticate-your-code-to-your-viam-app-location), you can set each customer up with credentials to access the data from only their location, or you can create a dashboard showing data from all sensors in your entire organization. +The full code is available for reference on [GitHub](https://github.com/viam-labs/air-quality-fleet/blob/main/main.ts). -![The air quality dashboard you'll build. This one has PM2.5 readings from two different sensor machines displayed, and a key with categories of air quality.](/tutorials/air-quality-fleet/two-sensors.png) +{{< alert title="Tip" color="tip" >}} +If you'd like to graph your data using a Grafana dashboard, try our [Visualize Data with Grafana tutorial](/tutorials/services/visualize-data-grafana/) next. +{{< /alert >}} ### Set up your TypeScript project Complete the following steps on your laptop or desktop. You don't need to install or edit anything else on your machine's single-board computer (aside from `viam-server` which you already did); you'll be running the TypeScript code from your personal computer. -1. Make sure you have the latest version of [Node.JS](https://nodejs.org/en) installed on your computer. -1. Install the Viam TypeScript SDK by running the following command in your terminal: - - ```sh {class="command-line" data-prompt="$"} - npm install --save @viamrobotics/sdk - ``` - -1. Create a directory on your laptop or desktop for your project. - Name it aqi-dashboard. - -1. Create a file in your aqi-dashboard folder and name it package.json. - The package.json file holds necessary metadata about your project. - Paste the following contents into it: - - ```json {class="line-numbers linkable-line-numbers"} - { - "name": "air-quality-dashboard", - "description": "A dashboard for visualizing data from air quality sensors.", - "scripts": { - "start": "esbuild ./main.ts --bundle --outfile=static/main.js --servedir=static --format=esm", - "test": "echo \"Error: no test specified\" && exit 1" - }, - "author": "", - "license": "ISC", - "devDependencies": { - "esbuild": "*" - }, - "dependencies": { - "@viamrobotics/sdk": "^0.13.0", - "bson": "^6.6.0" - } - } - ``` +{{< table >}} +{{% tablestep number=1 %}} + +Make sure you have the latest version of [Node.JS](https://nodejs.org/en) installed on your computer. + +{{% /tablestep %}} +{{% tablestep number=2 %}} + +Create a directory on your laptop or desktop for your project. +Name it aqi-dashboard. + +{{% /tablestep %}} +{{% tablestep number=3 %}} + +Create a file in your aqi-dashboard folder and name it package.json. +The package.json file holds necessary metadata about your project. +Paste the following contents into it: + +```json {class="line-numbers linkable-line-numbers"} +{ + "name": "air-quality-dashboard", + "description": "A dashboard for visualizing data from air quality sensors.", + "scripts": { + "start": "esbuild ./main.ts --bundle --outfile=static/main.js --servedir=static --format=esm", + "build": "esbuild ./main.ts --bundle --outfile=static/main.js --format=esm" + }, + "author": "", + "license": "ISC", + "devDependencies": { + "esbuild": "*" + }, + "dependencies": { + "@viamrobotics/sdk": "^0.42.0", + "bson": "^6.6.0", + "js-cookie": "^3.0.5" + } +} +``` {{% alert title="Fun fact" color="info" %}} + The `--format=esm` flag in the `"start"` script is important because the ECMAScript module format is necessary to support the BSON dependency this project uses for data query formatting. If you don't know what the proceeding sentence means, don't worry about it; just copy-paste the JSON above and it'll work. -{{% /alert %}} - -### Authenticate your code to your Viam app location - -Your TypeScript code requires an API key to establish a connection to your machines. -You can set up credentials to access data from all the sensor machines in your organization, or from just one location. -These API keys only need [**Operator** permissions](/manage/manage/rbac/). -In our example you could create a dashboard for Antonia with an API key to see the data from her location, and create a separate dashboard for RobotsRUs with a different API key to access the data from their location. -If RobotsRUs wanted to separate their dashboards by sub-locations, you could set up API keys for RobotsRUs to access data for each of their sub-locations separately, or you could modify the example code to filter data by location name. - -You can then either deploy each dashboard on a web server you manage, or add a web server on one machine per customer that hosts the dashboard for the respective customer so that they can access their data on their local network. -We leave this step to the reader. +{{% /alert %}} -The following instructions describe how to set up an API key for one location. +{{% /tablestep %}} +{{% tablestep number=4 %}} -1. Create another file inside the aqi-dashboard folder and name it main.ts. - Paste the following code into main.ts: +Install the project's dependencies by running the following command in your terminal: - ```typescript {class="line-numbers linkable-line-numbers"} - // Air quality dashboard +```sh {class="command-line" data-prompt="$"} +npm install +``` - import * as VIAM from "@viamrobotics/sdk"; - import { BSON } from "bson"; +{{% /tablestep %}} +{{< /table >}} - async function main() { - const opts: VIAM.ViamClientOptions = { - credential: { - type: "api-key", - // Key with location operator permissions - // Replace (including angle brackets) - payload: "", - // Replace (including angle brackets) - authEntity: "", - }, - }; +### Authenticate your code to your Viam app location - const orgID: string = ""; // Replace - const locationID: string = ""; // Replace +Your TypeScript code requires an API key to establish a connection to your machines. +In the final dashboard, these will be provided to your webapp through the local storage of your browser. +For development purposes, you will use an API key for your development machine. - // +{{< table >}} +{{% tablestep number=1 %}} - // - } +Create another file inside the aqi-dashboard folder and name it main.ts. +Paste the following code into main.ts: - // +```typescript {class="line-numbers linkable-line-numbers"} +// Air quality dashboard - main().catch((error) => { - console.error("encountered an error:", error); - }); - ``` +import * as VIAM from "@viamrobotics/sdk"; +import { BSON } from "bson"; +import Cookies from "js-cookie"; -1. Now you need to get the API key and the {{< glossary_tooltip term_id="organization" text="organization" >}} and {{< glossary_tooltip term_id="location" text="location" >}} IDs to replace the placeholder strings in the code you just pasted. +let apiKeyId = ""; +let apiKeySecret = ""; +let hostname = ""; +let machineId = ""; - In the [Viam app](https://app.viam.com), navigate to the location page for the location containing your air quality machines. +async function main() { + const opts: VIAM.ViamClientOptions = { + serviceHost: "https://app.viam.com", + credentials: { + type: "api-key", + payload: apiKeySecret, + authEntity: apiKeyId, + }, + }; - ![The location secret with a Copy button next to it.](/tutorials/air-quality-fleet/loc-secret-button.png) + // - Copy the **Location ID** and paste it into your code in place of ``, so that the line resembles `const orgID: string = "abcde12345"`. + // +} -1. Use the dropdown menu in the upper-right corner of the page to navigate to your organization settings page. - Copy the **Organization ID** found under **Details** near the top of the page. - Paste it in place of `` in your code. +// -1. Under the **API Keys** heading, click **Generate Key**. +document.addEventListener("DOMContentLoaded", async () => { + machineId = window.location.pathname.split("/")[2]; + ({ + id: apiKeyId, + key: apiKeySecret, + hostname: hostname, + } = JSON.parse(Cookies.get(machineId)!)); -1. Name your key something such as `air-sensors-key`. + main().catch((error) => { + console.error("encountered an error:", error); + }); +}); +``` -1. Select **Entity** and choose the location you have all your air quality sensing machines in. +{{% /tablestep %}} +{{% tablestep number=2 %}} -1. Set the **Role** to **Owner**, then click **Generate key**. +To test the dashboard with your development machine, you can temporarily set your machine's API key, API key ID and machine ID at the top of the `main()` function. -1. Copy the ID and corresponding key you just created and paste them in place of `` and `` in your code. - For example, you'll now have something of the form +You can obtain your API key and API key ID from your machines **CONNECT** tab. +You can copy the machine ID using the **...** menu at the top right and clicking **Copy machine ID**. - ```json {class="line-numbers linkable-line-numbers"} - authEntity: '1234abcd-123a-987b-1234567890abc', - payload: 'abcdefg987654321abcdefghi' - ``` +{{% snippet "secret-share.md" %}} - {{% snippet "secret-share.md" %}} +{{% /tablestep %}} +{{< /table >}} ### Add functionality to your code -1. Now that you have the API key and org and location IDs, you are ready to add code that establishes a connection from the computer running the code to the Viam Cloud where the air quality sensor data is stored. - You'll create a Viam `dataClient` instance which accesses all the data in your location, and then query this data to get only the data tagged with the `air-quality` tag you applied with your data service configuration. - The following code also queries the data for a list of the machines that have collected air quality data so that later, you can make a dashboard that has a place for the latest data from each of them. - - Paste the following code into the main function of your main.ts script, directly after the `locationID` line, in place of `// `: - - ```typescript {class="line-numbers linkable-line-numbers"} - // Instantiate data_client and get all - // data tagged with "air-quality" from your location - const client = await VIAM.createViamClient(opts); - const myDataClient = client.dataClient; - const query = { - $match: { - tags: "air-quality", - location_id: locationID, - organization_id: orgID, - }, - }; - const match = { $group: { _id: "$robot_id" } }; - // Get a list of all the IDs of machines that have collected air quality data - const BSONQueryForMachineIDList = [ - BSON.serialize(query), - BSON.serialize(match), - ]; - let machineIDs: any = await myDataClient?.tabularDataByMQL( - orgID, - BSONQueryForMachineIDList, - ); - // Get all the air quality data - const BSONQueryForData = [BSON.serialize(query)]; - let thedata: any = await myDataClient?.tabularDataByMQL( - orgID, - BSONQueryForData, - ); - ``` - -1. For this project, your dashboard will display the average of the last five readings from each air sensor. - You need a function to calculate that average. - The data returned by the query is not necessarily returned in order, so this function must put the data in order based on timestamps before averaging the last five readings. - - Paste the following code into main.ts after the end of your main function, in place of `// `: - - ```typescript {class="line-numbers linkable-line-numbers"} - // Get the average of the last few readings from a given sensor - async function getLastFewAv(alltheData: any[], machineID: string) { - // Get just the data from this machine - let thedata = new Array(); - for (const entry of alltheData) { - if (entry.robot_id == machineID) { - thedata.push({ - PM25: entry.data.readings["pm_2_5"], - time: entry.time_received, - }); - } - } - - // Sort the air quality data from this machine - // by timestamp - thedata = thedata.sort(function (a, b) { - let x = a.time.toString(); - let y = b.time.toString(); - if (x < y) { - return -1; - } - if (x > y) { - return 1; - } - return 0; - }); - - // Add up the last 5 readings collected. - // If there are fewer than 5 readings, add all of them. - let x = 5; // The number of readings to average over - if (x > thedata.length) { - x = thedata.length; - } - let total = 0; - for (let i = 1; i <= x; i++) { - const reading: number = thedata[thedata.length - i].PM25; - total += reading; - } - // Return the average of the last few readings - return total / x; - } - ``` - -1. Now that you've defined the function to sort and average the data for each machine, you're done with all the `dataClient` code. - The final piece you need to add to this script is a way to create some HTML to display data from each machine in your dashboard. - - Paste the following code into the main function of main.ts, in place of `// `: - - ```typescript {class="line-numbers linkable-line-numbers"} - // Instantiate the HTML block that will be returned - // once everything is appended to it - let htmlblock: HTMLElement = document.createElement("div"); - - // Display the relevant data from each machine to the dashboard - for (const mach of machineIDs) { - let insideDiv: HTMLElement = document.createElement("div"); - let avgPM: number = await getLastFewAv(thedata, mach._id); - // Color-code the dashboard based on air quality category - let level: string = "blue"; - switch (true) { - case avgPM < 12.1: { - level = "good"; - break; - } - case avgPM < 35.5: { - level = "moderate"; - break; - } - case avgPM < 55.5: { - level = "unhealthy-sensitive"; - break; - } - case avgPM < 150.5: { - level = "unhealthy"; - break; - } - case avgPM < 250.5: { - level = "very-unhealthy"; - break; - } - case avgPM >= 250.5: { - level = "hazardous"; - break; - } - } - // Create the HTML output for this machine - insideDiv.className = "inner-div " + level; - insideDiv.innerHTML = - "

" + - mach._id + - ": " + - avgPM.toFixed(2).toString() + - " μg/m3

"; - htmlblock.appendChild(insideDiv); - } - - // Output a block of HTML with color-coded boxes for each machine - return document.getElementById("insert-readings").replaceWith(htmlblock); - ``` - -The full code is available for reference on [GitHub](https://github.com/viam-labs/air-quality-fleet/blob/main/main.ts). +{{< table >}} +{{% tablestep number=1 %}} + +Now that you have the connection code, you are ready to add code that establishes a connection from the computer running the code to the Viam Cloud where the air quality sensor data is stored. +You'll first create a client to obtain the organization and location ID. Then you'll get a `dataClient` instance which accesses all the data in your location, and then query this data to get only the data tagged with the `air-quality` tag you applied with your data service configuration. +The following code also queries the data for a list of the machines that have collected air quality data so that later, depending on the API key used with the code, your dashboard can show the data from any number of machines. + +Paste the following code into the main function of your main.ts script, directly after the `locationID` line, in place of `// `: + +```typescript {class="line-numbers linkable-line-numbers"} +// Instantiate data_client and get all +// data tagged with "air-quality" from your location +const client = await VIAM.createViamClient(opts); +const machine = await client.appClient.getRobot(machineId); +const locationID = machine?.location; +const orgID = (await client.appClient.listOrganizations())[0].id; + +const myDataClient = client.dataClient; +const query = { + $match: { + tags: "air-quality", + location_id: locationID, + organization_id: orgID, + }, +}; +const match = { $group: { _id: "$robot_id" } }; +// Get a list of all the IDs of machines that have collected air quality data +const BSONQueryForMachineIDList = [ + BSON.serialize(query), + BSON.serialize(match), +]; +let machineIDs: any = await myDataClient?.tabularDataByMQL( + orgID, + BSONQueryForMachineIDList, +); +// Get all the air quality data +const BSONQueryForData = [BSON.serialize(query)]; +let measurements: any = await myDataClient?.tabularDataByMQL( + orgID, + BSONQueryForData, +); +``` + +{{% /tablestep %}} +{{% tablestep number=2 %}} + +For this project, your dashboard will display the average of the last five readings from each air sensor. +You need a function to calculate that average. +The data returned by the query is not necessarily returned in order, so this function must put the data in order based on timestamps before averaging the last five readings. + +Paste the following code into main.ts after the end of your main function, in place of `// `: + +```typescript {class="line-numbers linkable-line-numbers"} +// Get the average of the last five readings from a given sensor +async function getLastFewAv(all_measurements: any[], machineID: string) { + // Get just the data from this machine + let measurements = new Array(); + for (const entry of all_measurements) { + if (entry.robot_id == machineID) { + measurements.push({ + PM25: entry.data.readings["pm_2.5"], + time: entry.time_received, + }); + } + } + + // Sort the air quality data from this machine + // by timestamp + measurements = measurements.sort(function (a, b) { + let x = a.time.toString(); + let y = b.time.toString(); + if (x < y) { + return -1; + } + if (x > y) { + return 1; + } + return 0; + }); + + // Add up the last 5 readings collected. + // If there are fewer than 5 readings, add all of them. + let x = 5; // The number of readings to average over + if (x > measurements.length) { + x = measurements.length; + } + let total = 0; + for (let i = 1; i <= x; i++) { + const reading: number = measurements[measurements.length - i].PM25; + total += reading; + } + // Return the average of the last few readings + return total / x; +} +``` + +{{% /tablestep %}} +{{% tablestep number=3 %}} + +Now that you've defined the function to sort and average the data for each machine, you're done with all the `dataClient` code. +The final piece you need to add to this script is a way to create some HTML to display data from each machine in your dashboard. + +Paste the following code into the main function of main.ts, in place of `// `: + +```typescript {class="line-numbers linkable-line-numbers"} +// Instantiate the HTML block that will be returned +// once everything is appended to it +let htmlblock: HTMLElement = document.createElement("div"); + +// Display the relevant data from each machine to the dashboard +for (let m of machineIDs) { + let insideDiv: HTMLElement = document.createElement("div"); + let avgPM: number = await getLastFewAv(measurements, m._id); + // Color-code the dashboard based on air quality category + let level: string = "blue"; + switch (true) { + case avgPM < 12.1: { + level = "good"; + break; + } + case avgPM < 35.5: { + level = "moderate"; + break; + } + case avgPM < 55.5: { + level = "unhealthy-sensitive"; + break; + } + case avgPM < 150.5: { + level = "unhealthy"; + break; + } + case avgPM < 250.5: { + level = "very-unhealthy"; + break; + } + case avgPM >= 250.5: { + level = "hazardous"; + break; + } + } + let machineName = (await client.appClient.getRobot(m._id))?.name; + // Create the HTML output for this machine + insideDiv.className = "inner-div " + level; + insideDiv.innerHTML = + "

" + + machineName + + ": " + + avgPM.toFixed(2).toString() + + " μg/m3

"; + htmlblock.appendChild(insideDiv); +} + +// Output a block of HTML with color-coded boxes for each machine +return document.getElementById("insert-readings")?.replaceWith(htmlblock); +``` + +{{% /tablestep %}} +{{< /table >}} ### Style your dashboard @@ -773,13 +813,11 @@ If you look at line 5 of package.json, you can see that `./main.ts` } ``` - Feel free to adjust any of the colors, margins, fonts, and other specifications in style.css based on your preferences. - -## Full tutorial code +### Full tutorial code You can find all the code in the [GitHub repo for this tutorial](https://github.com/viam-labs/air-quality-fleet). -## Run the code +### Run the code 1. In a command prompt terminal, navigate to your aqi-dashboard directory. Run the following command to start up your air quality dashboard: @@ -788,7 +826,7 @@ You can find all the code in the [GitHub repo for this tutorial](https://github. npm start ``` - ![Terminal window with the command 'npm start' run inside the aqi-dashboard folder. The output says 'start' and then 'esbuild' followed by the esbuild string from the package.json file you configured. Then there's 'Local:' followed by a URL and 'Network:' followed by a different URL.](/tutorials/air-quality-fleet/terminal-url.png) + {{}} 1. The terminal should output a line such as `Local: http://127.0.0.1:8000/`. Copy the URL the terminal displays and paste it into the address bar in your web browser. @@ -797,28 +835,238 @@ You can find all the code in the [GitHub repo for this tutorial](https://github. ![Air quality dashboard in a web browser with PM2.5 readings from three different sensor machines displayed.](/tutorials/air-quality-fleet/three-sensor-dash.png) - Great work. - You've learned how to configure a fleet of machines, sync their data to one place, and pull that data into a custom dashboard using TypeScript. +Great work. +You've learned how to configure a machine and you can view its data in a custom TypeScript dashboard. + +### Deploy the app to Viam apps + +Let's deploy this dashboard so you don't have to run it locally. +This will also allow others to use the dashboard. + +{{< table >}} +{{% tablestep number=1 %}} + +**Remove any API key or IDs before continuing.** + +{{% /tablestep %}} +{{% tablestep number=2 %}} + +**Create a meta.json** in your project folder using this template: + +```json +{ + "module_id": ":air-quality", + "visibility": "public", + "url": "https://github.com/viam-labs/air-quality-fleet/", + "description": "Display air quality data from a machine", + "applications": [ + { + "name": "air-quality", + "type": "single_machine", + "entrypoint": "static/index.html" + } + ] +} +``` + +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. +Replace `` with your public namespace. + +{{% /tablestep %}} +{{% tablestep number=3 %}} + +**Register your module** with Viam: + +```sh {class="command-line" data-prompt="$" data-output="3-10"} +viam module create --name="air-quality" --public-namespace="your-namespace" +``` + +{{% /tablestep %}} +{{% tablestep number=4 %}} + +**Package your static files and your meta.json file and upload them** to the Viam Registry: + +```sh {class="command-line" data-prompt="$" data-output="3-10"} +npm run build +tar -czvf module.tar.gz static meta.json +viam module upload --upload=module.tar.gz --platform=any --version=0.0.1 +``` + +For subsequent updates run these commands again with an updated version number. + +{{% /tablestep %}} +{{% tablestep number=5 %}} + +**Try your app** by navigating to: + +``` +https://air-quality_your-public-namespace.viamapplications.com +``` + +Log in and select your development machine. +Your dashboard should now load your data. + +{{% /tablestep %}} +{{< /table >}} + +## Organizing devices for third-party usage + +Imagine you create an air quality monitoring company called Pollution Monitoring Made Simple. +Anyone can sign up and order one of your sensing machines. +When a new customer signs up, you assemble a new machine with a sensor, SBC, and power supply. + +Before shipping the sensor machine to your new client, you provision the machine, so that the recipient only needs to connect the machine to their WiFi network for it to work. + +To manage all your company's air quality sensing machines together, you create one organization called Pollution Monitoring Made Simple. +An organization is the highest level grouping, and often contains all the locations (and machines) of an entire company. + +Inside that organization, you create a location for each customer. +A location can represent either a physical location or some other conceptual grouping. +You have some individual customers, for example Antonia, who has one sensor machine in her home and one outside. +You have other customers who are businesses, for example RobotsRUs, who have two offices, one in New York and one in Oregon, with multiple sensor machines in each. + +Organization and locations allow you to manage permissions: + +- When you provision Antonia's machines, you create them inside a new location called `Antonia's Home` and grant Antonia operator access to the location. + This will later allow her to view data from the air sensors at her home. +- When you provision the machines for RobotsRUs, you create a location called `RobotsRUs` and two sub-locations for `New York Office` and `Oregon Office`. + Then you create the machines in the sub-locations and grant RobotsRUs operator access to the `RobotsRUs` machines location. + +You, as the organization owner, will be able to manage any necessary configuration changes for all air sensing machines in all locations created within the Pollution Monitoring Made Simple organization. + +{{}} + +For more information, see [Fleet Management](/manage/reference/organize/) and [provisioning](/manage/fleet/provision/setup/). + +### Organize your fleet + +If you want to follow along, create the following locations: + +- `Antonia's Home` +- `RobotsRUs` + +For `RobotsRUs` crate two sublocations: + +1. Add a new location called `Oregon Office` using the same **Add location** button. +1. Then, find the **New parent location** dropdown on the Oregon Office page. +1. Select **RobotsRUs** and click **Change**. + +Repeat to add the New York office: Add a new location called `New York Office`, then change its parent location to **RobotsRUs**. + +{{}} + +## Getting machines ready for third parties + +Continuing with our ficticious company, let's assume you want to ship air sensing machines to customers as ready-to-go as possible. +In other words, you want to provision devices. + +Before an air sensing machine leaves your factory, you'd complete the following steps: + +1. You'd flash the single-board computer with an operating system +2. You'd install `viam-agent` +3. You'd provide a machine configuration template, a fragment. + +Once a customer receives your machine, they will: + +1. Plug it in and turn it on. +2. `viam-agent` will start a WiFi network +3. The customer uses another device to connect to the machine's WiFi network and the user gives the machine the password for their WiFi network. +4. The machine can now connect to the internet and complete setup based on the fragment it knows about. + +### Create the fragment air sensing machines + +In this section you will create the {{< glossary_tooltip term_id="fragment" text="fragment" >}}, that is the configuration template that all other machines will use. + +1. Navigate to the **FLEET** page and go to the [**FRAGMENTS** tab](https://app.viam.com/fragments). +1. Add the same components that you added to the development machine when you [set up one device for development](#set-up-one-device-for-development). +1. As a shortcut, you can use the JSON mode on the machine you already configured and copy the machine's configuration to the fragment. + +{{< alert title="Tip: Use the fragment on your development machine" color="tip" >}} +To avoid differences between fragment and development machines, we recommend you remove the configured resources from the development machine and add the fragment you just created instead. +{{< /alert >}} + +### Provision your machines + +{{< table >}} +{{% tablestep number=1 %}} + +For each machine, flash the operating system to the device's SD card. +If you are using the Raspberry PI Imager, you **must customize at least the hostname** for the next steps to work. + +Then run the following commands to download the preinstall script and make the script executable: + +```sh {class="command-line" data-prompt="$"} +wget https://storage.googleapis.com/packages.viam.com/apps/viam-agent/preinstall.sh +chmod 755 preinstall.sh +``` + +{{% /tablestep %}} +{{% tablestep number=2 %}} + +Create a file called viam-defaults.json with the following configuration: + +```json {class="line-numbers linkable-line-numbers"} +{ + "network_configuration": { + "manufacturer": "Pollution Monitoring Made Simple", + "model": "v1", + "fragment_id": "", + "hotspot_prefix": "air-quality", + "hotspot_password": "WeLoveCleanAir123" + } +} +``` + +Replace `""` with the fragment ID from your fragment. + +{{% /tablestep %}} +{{% tablestep number=3 %}} + +In [Organize your fleet](#organize-your-fleet) you created several locations. +Navigate to one of the locations and create a machine. +Select the part status dropdown to the right of your machine's name on the top of the page. + +Click the copy icon next to **Machine cloud credentials**. +Paste the machine cloud credentials into a file on your harddrive called FILE>viam.json. + +{{< alert title="Tip: Fleet management API" color="tip" >}} +You can create locations and machines programmatically, with the [Fleet management API](/dev/reference/apis/fleet/). +{{< /alert >}} + +{{% /tablestep %}} +{{% tablestep number=3 %}} + +**Run the preinstall script** + +Run the preinstall script without options and it will attempt to auto-detect a mounted root filesystem (or for Raspberry Pi, bootfs) and also automatically determine the architecture. + +```sh {class="command-line" data-prompt="$"} +sudo ./preinstall.sh +``` + +Follow the instructions and provide the viam-defaults.json file and the machine cloud credentials file when prompted. + +{{% /tablestep %}} +{{< /table >}} + +That's it! Your device is now provisioned and ready for your end user! + +Having trouble? See [Provisioning](/manage/fleet/provision/setup/) for more information and troubleshooting.
## Next steps -Now that you can monitor your air quality, you can try to improve it and see if your efforts are effective. -You might try putting an air filter in your home or office and comparing the air quality data before you start running the filter with air quality after you have run the filter for a while. -Or, try sealing gaps around doors, and check whether your seal is working by looking at your dashboard. +You can now set up one or more air quality sensors for yourself or others and access them with your dashboard. +If you are selling your air quality sensing machines, they can also use your dashboard to view _their_ data. -You could set up a text or email alert when your air quality passes a certain threshold. +If you're wondering what to do next, why not set up a text or email alert when your air quality passes a certain threshold? For instructions on setting up an email alert, see the [Monitor Helmet Usage tutorial](/tutorials/projects/helmet/) as an example. For an example of setting up text alerts, see the [Detect a Person and Send a Photo tutorial](/tutorials/projects/send-security-photo/). -For another example of a custom TypeScript interface, check out the [Claw Game tutorial](/tutorials/projects/claw-game/). -Instead of displaying data, the claw game interface has buttons to control a robotic arm. - -In this tutorial we covered configuring a fleet of machines using fragments, but to automate the setup process further, you can [use the Viam Agent to provision machines](/manage/fleet/provision/setup/). - {{< cards >}} -{{% card link="/manage/fleet/provision/end-user-setup/" %}} -{{% card link="/tutorials/services/visualize-data-grafana/" %}} {{% card link="/tutorials/projects/helmet/" %}} +{{% card link="/tutorials/projects/send-security-photo/" %}} +{{% card link="/tutorials/services/visualize-data-grafana/" %}} {{< /cards >}} From be8a8d8d562141ae870b14afeb1a701ac7cba3d0 Mon Sep 17 00:00:00 2001 From: Naomi Pentrel <5212232+npentrel@users.noreply.github.com> Date: Tue, 27 May 2025 16:44:04 +0200 Subject: [PATCH 2/4] Update --- .../air-quality-fleet/add-fragment.png | Bin 114315 -> 0 bytes docs/tutorials/control/air-quality-fleet.md | 611 ++++++++---------- 2 files changed, 268 insertions(+), 343 deletions(-) delete mode 100644 assets/tutorials/air-quality-fleet/add-fragment.png diff --git a/assets/tutorials/air-quality-fleet/add-fragment.png b/assets/tutorials/air-quality-fleet/add-fragment.png deleted file mode 100644 index 91454c5bad4bc0c4cab14b417e6993517ba70d4f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 114315 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 CGp;89 diff --git a/docs/tutorials/control/air-quality-fleet.md b/docs/tutorials/control/air-quality-fleet.md index dba7617363..c84ffbd43e 100644 --- a/docs/tutorials/control/air-quality-fleet.md +++ b/docs/tutorials/control/air-quality-fleet.md @@ -54,6 +54,8 @@ For each machine, you need the following hardware: In this section we'll set up one air sensing machine as our development device. +### Create your machine + {{< table >}} {{% tablestep number=1 %}} @@ -94,7 +96,14 @@ Follow the **Set up your machine part** instructions to install `viam-server` on When your machine shows as connected, continue to the next step. {{% /tablestep %}} -{{% tablestep number=6 %}} + +{{< /table >}} + +### Configure your sensor + +{{< table >}} + +{{% tablestep number=1 %}} Navigate to the **CONFIGURE** tab of the machine, click the **+** button and select **Component or service**. Click **sensor**, then search for `sds011` and add the **sds001:v1** {{< glossary_tooltip term_id="module" text="module" >}}. @@ -103,7 +112,7 @@ Name the sensor `PM_sensor` and click **Create**. {{}} {{% /tablestep %}} -{{% tablestep number=7 %}} +{{% tablestep number=2 %}} In the newly created **PM_sensor** card, replace the contents of the attributes box (the empty curly braces `{}`) with the following: @@ -114,7 +123,7 @@ In the newly created **PM_sensor** card, replace the contents of the attributes ``` {{% /tablestep %}} -{{% tablestep number=8 %}} +{{% tablestep number=3 %}} To figure out which port your sensor is connected to on your board, SSH to your board and run the following command: @@ -135,235 +144,51 @@ Now that you have found the identifier, put the full path to the device into you ``` {{% /tablestep %}} -{{% tablestep number=9 %}} +{{% tablestep number=4 %}} Save the config. {{}} {{% /tablestep %}} -{{% tablestep number=10 %}} +{{% tablestep number=5 %}} On your sensor configuration panel, click on the **TEST** panel to check that you are getting readings from your sensor. {{}} -If you do not see readings, check the **LOGS** tab for errors, double-check that serial communication is enabled on the single board computer, and check that the `usb_interface` path is correctly specified (click below). - -This is how you set up one machine. -If you are following along for the RobotsRUs business from our example, create additional machines in each sub-location, that is, in the `Oregon Office` location and in the `New York Office` location. - -## Set up your hardware - -{{% alert title="Note" color="note" %}} -If this were a real company and you were shipping air sensing machines to customers, you would have the customer plug in power to the machine wherever they are setting it up. -Since you already installed `viam-server`, once a customer connects the machine to power and sets up wifi, the machine will automatically re-connect to the Viam app and pull any configuration updates. -{{% /alert %}} - -For each sensing machine: - -1. Connect the PM sensor to a USB port on the machine's SBC. - -1. Position your sensing machines in strategic locations, and connect them to power. - Here are some ideas for where to place sensing machines: - - - At home: - - In an outdoor location protected from weather, such as under the eaves of your home - - In the kitchen, where cooking can produce pollutants - - Anywhere you spend lots of time indoors and want to measure exposure to pollutants - - At work: - - At your desk to check your exposure throughout the day - - Near a door or window to see whether pollutants are leaking in - -## Configure your air quality sensors +If you do not see readings, check the **LOGS** tab for errors, double-check that serial communication is enabled on the single board computer, and check that the `usb_interface` path is correctly specified. -You need to [configure](/operate/get-started/supported-hardware/#configure-hardware-on-your-machine) your hardware so that each of your machines can communicate with its attached air quality [sensor](/operate/reference/components/sensor/). - -No matter how many sensing machines you use, you can configure them efficiently by using a reusable configuration block called a _{{< glossary_tooltip term_id="fragment" text="fragment" >}}_. -Fragments are a way to share and manage identical machine configurations across multiple machines. -Instead of going through all the configuration steps for each machine, you'll start by configuring just one machine and create a fragment based on that machine's configuration. -Then, you'll add the fragment to each of your machines. -With all your machines configured using the same fragment, if you need to update the config in the future, you can just update the fragment and all machines will automatically get the update. - -{{< alert title="Note" color="note" >}} -If this was a real company, adding the fragment to each individual machine would quickly become tiring. -We're showing you how to do this manually as a learning device. -Once you understand how to configure machines and use fragments, you can use [Provisioning](/manage/fleet/provision/setup/) to automatically set up your devices. -{{< /alert >}} - -### Configure your first machine - -#### Configure the sensor - -1. Navigate to the **CONFIGURE** tab of the machine details page in the [Viam app](https://app.viam.com) for your first machine. -2. Click the **+** (Create) button and click **Component or service** from the dropdown. - Click **sensor**, then search for `sds011` and click **sds001:v1** from the results. -3. Click **Add module**. - This adds the {{< glossary_tooltip term_id="module" text="module" >}} that provides the sensor model that supports the specific hardware we are using for this tutorial. - - ![The Add Module button that appears after you click the model name.](/tutorials/air-quality-fleet/add-sensor-module.png) - -4. Give the sensor a name like `PM_sensor` and click **Create**. -5. In the newly created **PM_sensor** card, replace the contents of the attributes box (the empty curly braces `{}`) with the following: - - ```json {class="line-numbers linkable-line-numbers"} - { - "usb_interface": "" - } - ``` - -6. Now you need to figure out which port your sensor is connected to on your board. - SSH to your board and run the following command: - - ```sh{class="command-line" data-prompt="$"} - ls /dev/serial/by-id - ``` - - This should output a list of one or more USB devices attached to your board, for example `usb-1a86_USB_Serial-if00-port0`. - If the air quality sensor is the only device plugged into your board, you can be confident that the only device listed is the correct one. - If you have multiple devices plugged into different USB ports, you may need to choose one path and test it, or unplug something, to figure out which path to use. - - Now that you have found the identifier, put the full path to the device into your config, for example: - - ```json {class="line-numbers linkable-line-numbers"} - { - "usb_interface": "/dev/serial/by-id/usb-1a86_USB_Serial-if00-port0" - } - ``` - -7. Save the config. - Your machine config should now resemble the following: +{{% /tablestep %}} - ![Configure tab showing PM sensor and the sensor module configured.](/tutorials/air-quality-fleet/configured-sensor.png) +{{< /table >}} -#### Configure data capture and sync +### Configure data management You have configured the sensor so the board can communicate with it, but sensor data is not yet being saved anywhere. Viam's [data management service](/data-ai/capture-data/capture-sync/) lets you capture data locally from each sensor and then sync it to the cloud where you can access historical sensor data and see trends over time. -Once you configure the rest of your sensing machines, you'll be able to remotely access data from all sensors in all locations, and when you're ready, you can give customers [access](/manage/manage/access/) to the data from the sensors in their locations. - -Configure data capture and sync as follows: - -1. Click the **+** (Create) button and click **Component or service** from the dropdown. -2. Click **data management**. -3. Give your data manager a name such as the auto-populated name `data_manager-1` and click **Create**. -4. Toggle **Syncing** to the on position. - Set the sync interval to `0.05` minutes so that data syncs to the cloud every 3 seconds. - You can change the interval if you like, just don't make it too long or you will have to wait a long time before you see your data! -5. Let's add a tag to all your data so that you can query data from all your air quality sensors more easily in later steps. - In the **Tags** field, type `air-quality` and click **+ Tag: air-quality** when it appears to create a new tag. - This tag will now automatically be applied to all data collected by this data manager. -6. Now the data management service is available to any components on your machine, and you can set up data capture on the sensor: -7. On your **PM_sensor** card, click **Add method**. -8. From the **Type** dropdown, select **Readings**. -9. Set the **Frequency** to `0.1` readings per second. - This will capture air quality data once every ten seconds. - It is useful to capture data frequently for testing purposes, but you can always change this frequency later since you probably don't need to capture data this frequently all day forever. -10. Save the config. - -### Create a fragment - -{{% alert title="Note" color="note" %}} -If you are only using one air quality sensing machine for this tutorial, you do not need to create or use fragments, since fragments are useful only when configuring multiple machines. -You can skip to [Test your sensors](#test-your-sensors). -{{% /alert %}} +As you configure more sensing machines, you'll be able to remotely access data from all machines. -While you configured your machine with the builder UI, the Viam app generated a JSON configuration file with all your parameters. -This is the file that tells `viam-server` what resources are available to it and how everything is connected. -Click **JSON** in the upper-left corner of the **CONFIGURE** tab to view the generated JSON file. -You can manually edit this file instead of using the builder UI if you are familiar with JSON. - -In any case, now that the JSON is generated, you are ready to create a {{< glossary_tooltip term_id="fragment" text="fragment" >}}: - -1. Select and copy the entire contents of the JSON config. -2. Navigate to the **FLEET** page and go to the [**FRAGMENTS** tab](https://app.viam.com/fragments). -3. Click **Create fragment** and change your fragment's name by clicking on it. We used the name `air-sensing-machine`. -4. Replace the empty curly braces `{}` with the config you copied from your machine. -5. Click **Save**. -6. Now, you can actually delete the entire config from your machine! - In the next section, you will replace it with the fragment you just created so that it gets updated alongside all your other machines when you update the fragment in the future. - - Navigate back to your machine's **CONFIGURE** tab, select **JSON** mode, and delete the entire contents of the config. - When you try to save, you'll get an invalid JSON error because it can't be empty. - Put in a set of curly braces `{}` and then save the config successfully. - -### Add the fragment to all your machines - -Add the fragment you just created to each of your machines including the first one: - -1. Click the **+** button, then click **Insert fragment** in the dropdown menu. -2. Search for and click the name of your fragment, for example `air-sensing-machine`. - - ![The insert fragment UI.](/tutorials/air-quality-fleet/add-fragment.png) - -3. Click **Insert fragment**. - The module, sensor, and data manager will appear in your config. -4. Save the config. -5. Repeat these steps on the machine details page for each of your air quality sensing machines. - -## Test your sensors - -Now that all your hardware is configured, it's a good idea to make sure readings are being gathered by the sensors and sent to the cloud before proceeding with the tutorial. -For each machine: - -1. Go to the machine details page in the [Viam app](https://app.viam.com.) and navigate to the **CONTROL** tab. -2. Within the **Sensors** section, click **Get Readings** for the **PM_sensor**. - If the sensor software and hardware is working, you should see values populate the **Readings** column. - - ![The sensor readings on the control tab.](/tutorials/air-quality-fleet/get-readings.png) - - If you do not see readings, check the **LOGS** tab for errors, double-check that serial communication is enabled on the single board computer, and check that the `usb_interface` path is correctly specified (click below). - - {{< expand "Click here for usb_interface troubleshooting help" >}} - -If you only have one USB device plugged into each of your boards, the `usb_interface` value you configured in the sensor config is likely (conveniently) the same for all of your machines. -If not, you can use [fragment overwrite](/manage/fleet/reuse-configuration/#modify-fragment-settings-on-a-machine) to modify the value on any machine for which it is different: - -1. If you're not getting sensor readings from a given machine, check the path of the USB port using the same [process by which you found the first USB path](#usb-path). -2. If the path to your sensor on one machine is different from the one you configured in the fragment, add a fragment overwrite to the config of that machine to change the path without needing to remove the entire fragment. - Follow the [instructions to add a fragment overwrite](/manage/fleet/reuse-configuration/#modify-fragment-settings-on-a-machine) to your machine's config, using the following JSON template: - - ```json {class="line-numbers linkable-line-numbers"} - "fragment_mods": [ - { - "fragment_id": "", - "mods": [ - { - "$set": { - "components.PM_sensor.attributes.usb_interface": "" - } - } - ] - } - ], - ``` - - Replace the values with your fragment ID and with the USB path you identify. - If you named your sensor something other than `PM_sensor`, change the sensor name in the template above. - -3. Repeat this process for each machine that needs a different `usb_interface` value. - If you have lots of machines with one `usb_interface` value, and lots of machines with a second one, you might consider duplicating the fragment, editing that value, and using that second fragment instead of the first one for the applicable machines, rather than using a fragment overwrite for each of the machines. - You have options. - - {{< /expand >}} +{{< table >}} -{{% /tablestep %}} -{{% tablestep number=11 %}} +{{% tablestep number=1 %}} Click **+** and add the **data management** service. -Toggle **Syncing** to the on position and set the sync interval to `0.05` minutes so that data syncs to the cloud every 3 seconds. -Add a tag to all your data so that you can query data from all your air quality sensors more easily in later steps. -In the **Tags** field, type `air-quality` and click **+ Tag: air-quality** when it appears to create a new tag. -This tag will now automatically be applied to all data collected by this data manager. +On the data manager panel: + +- Toggle **Syncing** to the on position. +- Set the sync interval to `0.05` minutes (every 3 seconds). +- In the **Tags** field, add `air-quality`. + This tag will now automatically be applied to all data collected by this data manager which will make querying data easier. {{% /tablestep %}} -{{% tablestep number=12 %}} +{{% tablestep number=2 %}} On the **PM_sensor** panel, click **Add method** to add data capture. -- **Type** :**Readings**. -- **Frequency**: `0.1` +- **Type**: **Readings**. +- **Frequency**: `0.1` (every 10 seconds). Save the config. @@ -390,7 +215,7 @@ If you'd like to graph your data using a Grafana dashboard, try our [Visualize D ### Set up your TypeScript project Complete the following steps on your laptop or desktop. -You don't need to install or edit anything else on your machine's single-board computer (aside from `viam-server` which you already did); you'll be running the TypeScript code from your personal computer. +You don't need to install or edit anything else on your machine's single-board computer (aside from `viam-server` which you already did); you'll be developing your TypeScript app from your personal computer and deploying it to Viam. {{< table >}} {{% tablestep number=1 %}} @@ -450,11 +275,12 @@ npm install {{% /tablestep %}} {{< /table >}} -### Authenticate your code to your Viam app location +### Access machines from your app + +Viam apps provide access to a machine by placing its API key in your local storage. +You can access the data from your browser's local storage with the following code. -Your TypeScript code requires an API key to establish a connection to your machines. -In the final dashboard, these will be provided to your webapp through the local storage of your browser. -For development purposes, you will use an API key for your development machine. +Currently, Viam apps only provide access to single machines but in future you will be able to access entire locations or organization. {{< table >}} {{% tablestep number=1 %}} @@ -508,22 +334,95 @@ document.addEventListener("DOMContentLoaded", async () => { {{% /tablestep %}} {{% tablestep number=2 %}} -To test the dashboard with your development machine, you can temporarily set your machine's API key, API key ID and machine ID at the top of the `main()` function. +For developing your app on localhost, **add the same information to your browsers local storage**. + +Navigate to [Camera Viewer](https://air-quality_naomi.viamapplications.com/) and log in, then select your development machine. -You can obtain your API key and API key ID from your machines **CONNECT** tab. -You can copy the machine ID using the **...** menu at the top right and clicking **Copy machine ID**. +Open Developer tools, go to the console and paste the following JavaScript to obtain the cookies you need: -{{% snippet "secret-share.md" %}} +```js {class="line-numbers linkable-line-numbers" data-line=""} +function generateCookieSetterScript() { + // Get all cookies from current page + const currentCookies = document.cookie.split(";"); + let cookieSetterCode = "// Cookie setter script for localhost\n"; + cookieSetterCode += + "// Copy and paste this entire script into your browser console when on localhost\n\n"; + + // Process each cookie + let cookieCount = 0; + currentCookies.forEach((cookie) => { + if (cookie.trim()) { + // Extract name and value from the cookie + const [name, value] = cookie.trim().split("="); + + // Add code to set this cookie + cookieSetterCode += `document.cookie = "${name}=${value}; path=/";\n`; + cookieCount++; + } + }); + + // Add summary comment + cookieSetterCode += `\nconsole.log("Set ${cookieCount} cookies on localhost");\n`; + + // Display the generated code + console.log(cookieSetterCode); + + // Create a textarea element to make copying easier + const textarea = document.createElement("textarea"); + textarea.value = cookieSetterCode; + textarea.style.position = "fixed"; + textarea.style.top = "0"; + textarea.style.left = "0"; + textarea.style.width = "100%"; + textarea.style.height = "250px"; + textarea.style.zIndex = "9999"; + document.body.appendChild(textarea); + textarea.focus(); + textarea.select(); +} + +// Execute the function +generateCookieSetterScript(); +``` + +{{% /tablestep %}} +{{% tablestep number=3 %}} + +Copy the resulting script. It will look like this: + +```js {class="line-numbers linkable-line-numbers" data-line=""} +// Cookie setter script for localhost +// Copy and paste this entire script into your browser console when on localhost + +document.cookie = "; path=/"; +document.cookie = "machinesWhoseCredentialsAreStored=; path=/"; + +console.log("Set 2 cookies on localhost"); +``` + +{{% /tablestep %}} +{{% tablestep number=4 %}} + +Run the following command to serve the app you are building: + +```sh {class="command-line" data-prompt="$" data-output="2-10"} +npm run start +``` + +Open the app in your browser at `http://127.0.0.1:8000/`. + +Then, open developer tools, go to the console and paste the copied JavaScript code to set your cookies. {{% /tablestep %}} {{< /table >}} ### Add functionality to your code +Now that you have the connection code, you are ready to add code that establishes a connection from the computer running the code to the Viam Cloud where the air quality sensor data is stored. + {{< table >}} {{% tablestep number=1 %}} -Now that you have the connection code, you are ready to add code that establishes a connection from the computer running the code to the Viam Cloud where the air quality sensor data is stored. You'll first create a client to obtain the organization and location ID. Then you'll get a `dataClient` instance which accesses all the data in your location, and then query this data to get only the data tagged with the `air-quality` tag you applied with your data service configuration. The following code also queries the data for a list of the machines that have collected air quality data so that later, depending on the API key used with the code, your dashboard can show the data from any number of machines. @@ -689,129 +588,144 @@ Now, you'll create a page to display the data. The complete code is available on [GitHub](https://github.com/viam-labs/air-quality-fleet) as a reference. {{% /alert %}} -1. Create a folder called static inside your aqi-dashboard folder. - Inside the static folder, create a file called index.html. - This file specifies the contents of the webpage that you will see when you run your code. - Paste the following into index.html: - - ```{class="line-numbers linkable-line-numbers" data-line="11"} - - - - - - -
-
-

Air Quality Dashboard

-
- -
-

PM 2.5 readings

-

The following are averages of the last few readings from each machine:

-
-
-

Loading data... - It may take a few moments for the data to load. - Do not refresh page.

-
-
-
-

Key:

-

Good air quality

-

Moderate

-

Unhealthy for sensitive groups

-

Unhealthy

-

Very unhealthy

-

Hazardous

-
-

- After the data has loaded, you can refresh the page for the latest readings. -

+{{< table >}} +{{% tablestep number=1 %}} + +Create a folder called static inside your aqi-dashboard folder. +Inside the static folder, create a file called index.html. +This file specifies the contents of the webpage that you will see when you run your code. +Paste the following into index.html: + +```{class="line-numbers linkable-line-numbers" data-line="11"} + + + + + + +
+
+

Air Quality Dashboard

- - - ``` + +
+

PM 2.5 readings

+

The following are averages of the last few readings from each machine:

+
+
+

Loading data... + It may take a few moments for the data to load. + Do not refresh page.

+
+
+
+

Key:

+

Good air quality

+

Moderate

+

Unhealthy for sensitive groups

+

Unhealthy

+

Very unhealthy

+

Hazardous

+
+

+ After the data has loaded, you can refresh the page for the latest readings. +

+
+ + +``` {{% alert title="Fun fact" color="info" %}} + Line 11, highlighted above, is where the HTML output of the TypeScript file main.ts will get pulled in. TypeScript is a superset of JavaScript with added functionality, and it transpiles to JavaScript, which is why your file is called main.ts even though line 11 indicates `src="main.js"`. If you look at line 5 of package.json, you can see that `./main.ts` builds out to `static/main.js`. + {{% /alert %}} -2. Now you'll create a style sheet to specify the fonts, colors, and spacing of your dashboard. - Create a new file inside your static folder and name it style.css. -3. Paste the following into style.css: - - ```{class="line-numbers linkable-line-numbers"} - body { - font-family: Helvetica; - margin-left: 20px; - } - - div { - background-color: whitesmoke; - } - - h1 { - color: black; - } - - h2 { - font-family: Helvetica; - } - - .inner-div { - font-family: monospace; - border: .2px solid; - background-color: lightblue; - padding: 20px; - margin-top: 10px; - max-width: 320px; - font-size: large; - } - - .key { - max-width: 200px; - padding: 0px 5px 5px; - } - - .key p { - padding: 4px; - margin: 0px; - } - - .good { - background-color: lightgreen; - } - - .moderate { - background-color: yellow; - } - - .unhealthy-sensitive { - background-color: orange; - } - - .unhealthy { - background-color: red; - } - - .very-unhealthy { - background-color: violet; - } - - .hazardous { - color: white; - background-color: purple; - } - - #main { - max-width:600px; - padding:10px 30px 10px; - } - ``` +{{% /tablestep %}} +{{% tablestep number=2 %}} + +Now you'll create a style sheet to specify the fonts, colors, and spacing of your dashboard. +Create a new file inside your static folder and name it style.css. + +{{% /tablestep %}} +{{% tablestep number=3 %}} + +Paste the following into style.css: + +```{class="line-numbers linkable-line-numbers"} +body { + font-family: Helvetica; + margin-left: 20px; +} + +div { + background-color: whitesmoke; +} + +h1 { + color: black; +} + +h2 { + font-family: Helvetica; +} + +.inner-div { + font-family: monospace; + border: .2px solid; + background-color: lightblue; + padding: 20px; + margin-top: 10px; + max-width: 320px; + font-size: large; +} + +.key { + max-width: 200px; + padding: 0px 5px 5px; +} + +.key p { + padding: 4px; + margin: 0px; +} + +.good { + background-color: lightgreen; +} + +.moderate { + background-color: yellow; +} + +.unhealthy-sensitive { + background-color: orange; +} + +.unhealthy { + background-color: red; +} + +.very-unhealthy { + background-color: violet; +} + +.hazardous { + color: white; + background-color: purple; +} + +#main { + max-width:600px; + padding:10px 30px 10px; +} +``` + +{{% /tablestep %}} +{{< /table >}} ### Full tutorial code @@ -846,11 +760,6 @@ This will also allow others to use the dashboard. {{< table >}} {{% tablestep number=1 %}} -**Remove any API key or IDs before continuing.** - -{{% /tablestep %}} -{{% tablestep number=2 %}} - **Create a meta.json** in your project folder using this template: ```json @@ -874,7 +783,7 @@ Find the **Public namespace** and copy that string. Replace `` with your public namespace. {{% /tablestep %}} -{{% tablestep number=3 %}} +{{% tablestep number=2 %}} **Register your module** with Viam: @@ -883,11 +792,11 @@ viam module create --name="air-quality" --public-namespace="your-namespace" ``` {{% /tablestep %}} -{{% tablestep number=4 %}} +{{% tablestep number=3 %}} **Package your static files and your meta.json file and upload them** to the Viam Registry: -```sh {class="command-line" data-prompt="$" data-output="3-10"} +```sh {class="command-line" data-prompt="$" data-output=""} npm run build tar -czvf module.tar.gz static meta.json viam module upload --upload=module.tar.gz --platform=any --version=0.0.1 @@ -896,11 +805,11 @@ viam module upload --upload=module.tar.gz --platform=any --version=0.0.1 For subsequent updates run these commands again with an updated version number. {{% /tablestep %}} -{{% tablestep number=5 %}} +{{% tablestep number=4 %}} **Try your app** by navigating to: -``` +```txt https://air-quality_your-public-namespace.viamapplications.com ``` @@ -974,16 +883,32 @@ Once a customer receives your machine, they will: 3. The customer uses another device to connect to the machine's WiFi network and the user gives the machine the password for their WiFi network. 4. The machine can now connect to the internet and complete setup based on the fragment it knows about. -### Create the fragment air sensing machines +### Create the fragment for air sensing machines In this section you will create the {{< glossary_tooltip term_id="fragment" text="fragment" >}}, that is the configuration template that all other machines will use. 1. Navigate to the **FLEET** page and go to the [**FRAGMENTS** tab](https://app.viam.com/fragments). +1. Click Create fragment. +1. Name the fragment `air-quality-configuration`. 1. Add the same components that you added to the development machine when you [set up one device for development](#set-up-one-device-for-development). -1. As a shortcut, you can use the JSON mode on the machine you already configured and copy the machine's configuration to the fragment. + + As a shortcut, you can use the JSON mode on the machine you already configured and copy the machine's configuration to the fragment. + + {{< expand "Click here for info about the usb_interface value." >}} + +If you only have one USB device plugged into each of your boards, the `usb_interface` value you configured in the sensor config is likely (conveniently) the same for all of your machines. + +If not, you can use [fragment overwrite](/manage/fleet/reuse-configuration/#modify-fragment-settings-on-a-machine) to modify the value on any machine for which it is different. + +{{< /expand >}} + +1. Specify the version for the sds011 module. + At the point of writing the version is `0.2.1`. + Specifying a specific version or a specific minor or major version of a module will ensure that even if the module you use changes, your machines remain functional. + You can update your fragment at any point, any machines using it will update to use the new configuration. {{< alert title="Tip: Use the fragment on your development machine" color="tip" >}} -To avoid differences between fragment and development machines, we recommend you remove the configured resources from the development machine and add the fragment you just created instead. +To avoid differences between fragment and development machines, we recommend you remove the configured resources from the development machine and add the fragment you just created instead using the **+** button. {{< /alert >}} ### Provision your machines @@ -1035,7 +960,7 @@ You can create locations and machines programmatically, with the [Fleet manageme {{< /alert >}} {{% /tablestep %}} -{{% tablestep number=3 %}} +{{% tablestep number=4 %}} **Run the preinstall script** From 4a030e673ee2818a7591387880ce427c15dee62d Mon Sep 17 00:00:00 2001 From: Naomi Pentrel <5212232+npentrel@users.noreply.github.com> Date: Tue, 27 May 2025 16:58:25 +0200 Subject: [PATCH 3/4] Update --- docs/manage/reference/organize.md | 2 +- docs/tutorials/control/air-quality-fleet.md | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/docs/manage/reference/organize.md b/docs/manage/reference/organize.md index 8d85499129..b55af809cb 100644 --- a/docs/manage/reference/organize.md +++ b/docs/manage/reference/organize.md @@ -78,7 +78,7 @@ You can nest locations up to three levels deep. ## Example -If you'd like to look at an example, see [Monitor Air Quality with a Fleet of Sensors](/tutorials/control/air-quality-fleet/#example). +If you'd like to look at an example, see [Monitor Air Quality with a Fleet of Sensors](/tutorials/control/air-quality-fleet/#organizing-devices-for-third-party-usage). ## Frequently asked questions diff --git a/docs/tutorials/control/air-quality-fleet.md b/docs/tutorials/control/air-quality-fleet.md index c84ffbd43e..026a639c4a 100644 --- a/docs/tutorials/control/air-quality-fleet.md +++ b/docs/tutorials/control/air-quality-fleet.md @@ -867,7 +867,7 @@ Repeat to add the New York office: Add a new location called `New York Office`, ## Getting machines ready for third parties -Continuing with our ficticious company, let's assume you want to ship air sensing machines to customers as ready-to-go as possible. +Continuing with our fictitious company, let's assume you want to ship air sensing machines to customers as ready-to-go as possible. In other words, you want to provision devices. Before an air sensing machine leaves your factory, you'd complete the following steps: @@ -962,9 +962,7 @@ You can create locations and machines programmatically, with the [Fleet manageme {{% /tablestep %}} {{% tablestep number=4 %}} -**Run the preinstall script** - -Run the preinstall script without options and it will attempt to auto-detect a mounted root filesystem (or for Raspberry Pi, bootfs) and also automatically determine the architecture. +**Run the preinstall script** without options and it will attempt to auto-detect a mounted root filesystem (or for Raspberry Pi, bootfs) and also automatically determine the architecture. ```sh {class="command-line" data-prompt="$"} sudo ./preinstall.sh From 2a7049ecb49d3d8de37842b7aae8a3247086d484 Mon Sep 17 00:00:00 2001 From: Naomi Pentrel <5212232+npentrel@users.noreply.github.com> Date: Mon, 2 Jun 2025 12:14:49 +0200 Subject: [PATCH 4/4] Apply suggestions from code review Co-authored-by: Jessamy Taylor <75634662+JessamyT@users.noreply.github.com> --- docs/tutorials/control/air-quality-fleet.md | 39 ++++++++++++--------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/docs/tutorials/control/air-quality-fleet.md b/docs/tutorials/control/air-quality-fleet.md index 026a639c4a..92a0ba3a79 100644 --- a/docs/tutorials/control/air-quality-fleet.md +++ b/docs/tutorials/control/air-quality-fleet.md @@ -20,7 +20,7 @@ cost: 200 # 2. The reader can identify when to use fragments and evaluate when it is worth using fragments. # The reader can create their own fragments for their projects and knows what to include and exclude from them. # 3. The reader recognizes how permissions enable the management of data for a business across multiple customers while providing each customer access to their own data. -# 4. The reader can deploy custom frond ends that end users can use to operate their machines. +# 4. The reader can deploy custom front ends that end users can use to operate their machines. --- In this tutorial you will learn how to set up a fleet of devices for yourself or third parties to collect air quality data. @@ -34,7 +34,7 @@ By completing this project, you will learn to: - Organize your fleet using {{< glossary_tooltip term_id="location" text="locations" >}} - Collect and sync data from multiple machines - Use the Viam TypeScript SDK to query sensor data -- Create a custom dashboard that you and third parties can use to view data for their respective machines. +- Create a custom dashboard that you and third parties can use to view data for their respective machines {{< /alert >}} @@ -45,7 +45,7 @@ By completing this project, you will learn to: You can create one or more machines to measure air quality. For each machine, you need the following hardware: -- one or more [SDS011 Nova PM sensors](https://www.amazon.com/SDS011-Quality-Detection-Conditioning-Monitor/dp/B07FSDMRR5) +- One [SDS011 Nova PM sensors](https://www.amazon.com/SDS011-Quality-Detection-Conditioning-Monitor/dp/B07FSDMRR5) - If you choose to use a different air quality sensor, you may need to [create your own module](/operate/get-started/other-hardware/) implementing the [sensor API](/operate/reference/components/sensor/#api) for your specific hardware. - A single-board computer (SBC) [capable of running `viam-server`](https://docs.viam.com/installation/) - An appropriate power supply @@ -197,7 +197,8 @@ You can check that your sensor data is being synced by clicking on the **...** m {{% /tablestep %}} {{< /table >}} -Congratulations, if you made it this far, you now have a functional air sensing machine. +Congratulations. +If you made it this far, you now have a functional air sensing machine. Let's create a dashboard for its measurements next. ## Create a dashboard @@ -280,7 +281,7 @@ npm install Viam apps provide access to a machine by placing its API key in your local storage. You can access the data from your browser's local storage with the following code. -Currently, Viam apps only provide access to single machines but in future you will be able to access entire locations or organization. +Currently, Viam apps only provide access to single machines but in future you will be able to access entire locations or organizations. {{< table >}} {{% tablestep number=1 %}} @@ -334,11 +335,11 @@ document.addEventListener("DOMContentLoaded", async () => { {{% /tablestep %}} {{% tablestep number=2 %}} -For developing your app on localhost, **add the same information to your browsers local storage**. +For developing your app on localhost, **add the same information to your browser's local storage**. Navigate to [Camera Viewer](https://air-quality_naomi.viamapplications.com/) and log in, then select your development machine. -Open Developer tools, go to the console and paste the following JavaScript to obtain the cookies you need: +Open Developer Tools, go to the console and paste the following JavaScript to obtain the cookies you need: ```js {class="line-numbers linkable-line-numbers" data-line=""} function generateCookieSetterScript() { @@ -821,6 +822,8 @@ Your dashboard should now load your data. ## Organizing devices for third-party usage +The following example shows how you can use {{< glossary_tooltip term_id="organization" text="organizations" >}} and {{< glossary_tooltip term_id="location" text="locations" >}} to provide users access to the right groups of machines. + Imagine you create an air quality monitoring company called Pollution Monitoring Made Simple. Anyone can sign up and order one of your sensing machines. When a new customer signs up, you assemble a new machine with a sensor, SBC, and power supply. @@ -879,16 +882,16 @@ Before an air sensing machine leaves your factory, you'd complete the following Once a customer receives your machine, they will: 1. Plug it in and turn it on. -2. `viam-agent` will start a WiFi network +2. `viam-agent` will start a WiFi network. 3. The customer uses another device to connect to the machine's WiFi network and the user gives the machine the password for their WiFi network. 4. The machine can now connect to the internet and complete setup based on the fragment it knows about. ### Create the fragment for air sensing machines -In this section you will create the {{< glossary_tooltip term_id="fragment" text="fragment" >}}, that is the configuration template that all other machines will use. +In this section you will create the {{< glossary_tooltip term_id="fragment" text="fragment" >}}: the configuration template that all other machines will use. 1. Navigate to the **FLEET** page and go to the [**FRAGMENTS** tab](https://app.viam.com/fragments). -1. Click Create fragment. +1. Click **Create fragment**. 1. Name the fragment `air-quality-configuration`. 1. Add the same components that you added to the development machine when you [set up one device for development](#set-up-one-device-for-development). @@ -902,13 +905,13 @@ If not, you can use [fragment overwrite](/manage/fleet/reuse-configuration/#modi {{< /expand >}} -1. Specify the version for the sds011 module. +1. Specify the version for the `sds011` module. At the point of writing the version is `0.2.1`. Specifying a specific version or a specific minor or major version of a module will ensure that even if the module you use changes, your machines remain functional. - You can update your fragment at any point, any machines using it will update to use the new configuration. + You can update your fragment at any point, and any machines using it will update to use the new configuration. {{< alert title="Tip: Use the fragment on your development machine" color="tip" >}} -To avoid differences between fragment and development machines, we recommend you remove the configured resources from the development machine and add the fragment you just created instead using the **+** button. +To avoid differences between fragment and development machines, we recommend you remove the configured resources from the development machine, and instead use the **+** button to add the fragment you just created. {{< /alert >}} ### Provision your machines @@ -917,7 +920,7 @@ To avoid differences between fragment and development machines, we recommend you {{% tablestep number=1 %}} For each machine, flash the operating system to the device's SD card. -If you are using the Raspberry PI Imager, you **must customize at least the hostname** for the next steps to work. +If you are using the Raspberry Pi Imager, you **must customize at least the hostname** for the next steps to work. Then run the following commands to download the preinstall script and make the script executable: @@ -953,7 +956,7 @@ Navigate to one of the locations and create a machine. Select the part status dropdown to the right of your machine's name on the top of the page. Click the copy icon next to **Machine cloud credentials**. -Paste the machine cloud credentials into a file on your harddrive called FILE>viam.json. +Paste the machine cloud credentials into a file on your hard drive called FILE>viam.json. {{< alert title="Tip: Fleet management API" color="tip" >}} You can create locations and machines programmatically, with the [Fleet management API](/dev/reference/apis/fleet/). @@ -973,9 +976,11 @@ Follow the instructions and provide the viam-defaults.json file and {{% /tablestep %}} {{< /table >}} -That's it! Your device is now provisioned and ready for your end user! +That's it! +Your device is now provisioned and ready for your end user! -Having trouble? See [Provisioning](/manage/fleet/provision/setup/) for more information and troubleshooting. +Having trouble? +See [Provisioning](/manage/fleet/provision/setup/) for more information and troubleshooting.