diff --git a/docs/get-started/project-templates.md b/docs/get-started/project-templates.md index 1767ca5a..c6cee1ac 100644 --- a/docs/get-started/project-templates.md +++ b/docs/get-started/project-templates.md @@ -36,4 +36,14 @@ Project templates also provide a starting point for your own projects - our proj [Explore :octicons-arrow-right-24:](../tutorials/clickstream/overview.md) +- __Predictive maintenance__ + + --- + + ![Predictive maintenance pipeline](../images/project-templates/predictive-maintenance-pipeline.png) + + Predicts failures in 3D printers. + + [Explore :octicons-arrow-right-24:](../tutorials/predictive-maintenance/overview.md) + diff --git a/docs/images/project-templates/predictive-maintenance-pipeline.png b/docs/images/project-templates/predictive-maintenance-pipeline.png new file mode 100644 index 00000000..4053c88f Binary files /dev/null and b/docs/images/project-templates/predictive-maintenance-pipeline.png differ diff --git a/docs/tutorials/currency-alerting/currency-alerting.md b/docs/tutorials/currency-alerting/currency-alerting.md index eea78fc8..d89dd429 100644 --- a/docs/tutorials/currency-alerting/currency-alerting.md +++ b/docs/tutorials/currency-alerting/currency-alerting.md @@ -145,13 +145,13 @@ This microservice reads from the `currency-rate-alerts` topic and whenever a new It also reads the contents of the message and enriches the notification with details on how the threshold was crossed, that is, whether the price is moving up or down. -To set up the push nonfiction microservice, follow these steps: +To set up the push notification microservice, follow these steps: 1. Click on the `Code Samples` icon in the left-hand navigation. 2. In the search box on the Code Samples page, enter "Pushover". - You will see the `Threshold Alert` sample appear in the search results: + You will see the `Pushover Output` sample appear in the search results: ![Pushover Notifications](./images/library-pushover.png "Pushover Notifications") diff --git a/docs/tutorials/overview.md b/docs/tutorials/overview.md index df2f893d..a03732de 100644 --- a/docs/tutorials/overview.md +++ b/docs/tutorials/overview.md @@ -44,6 +44,18 @@ Some tutorials use [project templates](../get-started/project-templates.md) - th [Explore :octicons-arrow-right-24:](../tutorials/clickstream/overview.md) +- __Predictive maintenance__ + + --- + + ![Predictive maintenance pipeline](../images/project-templates/predictive-maintenance-pipeline.png) + + `Project template` + + Predicts failures in 3D printers. + + [Explore :octicons-arrow-right-24:](../tutorials/predictive-maintenance/overview.md) + - __Train and deploy machine learning (ML)__ --- diff --git a/docs/tutorials/predictive-maintenance/alert-service.md b/docs/tutorials/predictive-maintenance/alert-service.md new file mode 100644 index 00000000..b7a4978b --- /dev/null +++ b/docs/tutorials/predictive-maintenance/alert-service.md @@ -0,0 +1,104 @@ +# Alert service + +Sends alerts to an output topic when the temperature is under or over the threshold. + +It receives data from two topics (3d printer data and forecast) and triggers an alert (to output topic `alerts`) if the temperature is under or over the threshold. + +![pipline section](./images/alert-pipeline-segment.png) + +The default thresholds are as shown in the following table: + +| Variable | Default value (degrees C)| +|----|----| +| min_ambient_temperature | 45| +| max_ambient_temperature | 55 | +| min_bed_temperature | 105 | +| max_bed_temperature | 115 | +| min_hotend_temperature | 245 | +| max_hotend_temperature | 255 | + +These thresholds are used to determine if the temperature, or forecast temperature, are under or over the threshold values. If so these alerts are published to the `alerts` topic. + +Note there are different alert types, with the message format for the `no-alert` type alert: + +``` json +{ + "status": "no-alert", + "parameter_name": "hotend_temperature", + "message": "'Hotend temperature' is within normal parameters", + "alert_timestamp": 1701280033000000000, + "alert_temperature": 246.04148121958596 +} +``` + +An example of the `under-now` alert message format: + +``` json +{ + "status": "under-now", + "parameter_name": "bed_temperature", + "alert_timestamp": 1701273328000000000, + "alert_temperature": 104.0852349596566, + "message": "'Bed temperature' is under the threshold (105ΒΊC)" +} +``` + +Here's an `over-forecast` alert message format: + +``` json +{ + "status": "over-forecast", + "parameter_name": "forecast_fluctuated_ambient_temperature", + "alert_temperature": 55.014602460947586, + "alert_timestamp": 1701278280000000000, + "message": "'Ambient temperature' is forecasted to go over 55ΒΊC in 1:36:29." +} +``` + +Here's the `under-forecast` alert message format: + +``` json +{ + "status": "under-forecast", + "parameter_name": "forecast_fluctuated_ambient_temperature", + "alert_temperature": 44.98135836928914, + "alert_timestamp": 1701277320000000000, + "message": "'Ambient temperature' is forecasted to fall below 45ΒΊC in 1:20:28." +} +``` + +These alerts are subscribed to by the Printers dashboard service, and the alerts can be displayed in real time on the scrolling charts, as well as the scrolling alert display: + +![Alerts](./images/alerts-display.png) + +## Check the log messages + +It can be very useful to check the logs for a service. To do this from the pipeline view: + +1. Click on Alert Service in the pipeline view. + +2. Click the `Logs` tab. + +You can now view the log messages: + +![Log messages](./images/alert-service-logging.png) + +## View the message format + +You can also view the actual messages being transferred through the service: + +1. Click the `Messages` tab. + +2. You can now select either the input or oputput topic as required from the topic drop down: + + ![Topic drop down](./images/messages-topic-dropdown.png) + +3. You can now explore the messages. Click on a message to display it: + + ![Message format](./images/message-format.png) + + Make sure you click the `Live` tab to continue viewing live messages. + +## πŸƒβ€β™€οΈ Next step + +[Part 6 - InfluxDB raw data service :material-arrow-right-circle:{ align=right }](./influxdb-raw-data.md) diff --git a/docs/tutorials/predictive-maintenance/data-generator.md b/docs/tutorials/predictive-maintenance/data-generator.md new file mode 100644 index 00000000..6af24184 --- /dev/null +++ b/docs/tutorials/predictive-maintenance/data-generator.md @@ -0,0 +1,111 @@ +# Data generator + +This service generates temperature data simulating one or more 3D printers. It simulates three temperature sensors on a fleet of 3D printers. + +![data generator pipeline segment](./images/data-generator-pipeline-segment.png) + +For each printer, the enclosure temperature is programmed to decrease starting at the 4 hour point. It will drop below the minimum threshold of 45Β°C at 5h:47m β€” the failure point. + +The simulation speed is 10x actual spped, so the temperature will start to drop at approximately 24 minutes and cross the minimum threshold at around 34m 44s. + +When printing with a heat-sensitive material such as ABS (Acrylonitrile Butadiene Styrene), it’s important to ensure that the temperatures remain stable. + +The [forecasting algorithm](./forecast-service.md) that attempts to estimate when this is going to happen, and displays the alert on a dashboard. + +## Data published + +The generated data is published to the `3d-printer-data` topic: + +* Ambient temperature +* Ambient temperature with fluctuations +* Bed temperature +* Hot end temperature +* original_timestamp +* Printer finished printing + +This service runs continually. + +## Exploring the message format + +If you click `Topics` in the main left-hand navigation you see the topics in the environment. Click in the `Data` area to view live data. This takes you into the Quix data explorer. You can then select the stream and parameter data you'd like to explore. You can then view this data in either the `Table` or `Messages` view. + +If you look at the messages in the `Messages` view, you'll see data has the following format: + +``` json +{ + "Epoch": 0, + "Timestamps": [ + 1701277527000000000 + ], + "NumericValues": { + "hotend_temperature": [ + 250.8167407832582 + ], + "bed_temperature": [ + 106.9299672495977 + ], + "ambient_temperature": [ + 36.92387946005222 + ], + "fluctuated_ambient_temperature": [ + 36.92387946005222 + ] + }, + "StringValues": { + "original_timestamp": [ + "2023-11-29 17:05:27" + ] + }, + "BinaryValues": {}, + "TagValues": { + "printer": [ + "Printer 72" + ] + } +} +``` + +The Quix data explorer is a very useful tool for debugging and monitoring your pipeline. + +## Viewing the deployed application + +In the left-hand main navigation, click `Deployments` to see all the deployed services and jobs in the environment. Click `Data Generator` to select the deployment. This takes you to an extremely useful screen where you can: + +1. View the status of the deployment (such as CPU, memory usage, and replicas assigned). +2. See the live logs for the service. +3. See the topic lineage for the service. +4. Access Build logs (in case of errors when the service is built). +5. Access the Messages tab, where you can then see messages associated with the service in real time. + +## Viewing the application code + +There are many ways to view the code for the application (which is then deployed as a job or service). The quickest way from the current screen is to click the area shown: + +![Go to code view](./images/data-generator-deployment-code-view.png) + +You'll now be in the code view with the **version of the deployed code** displayed. + +Review the code, you'll see that data is generated for each printer, and each printer has its own stream for generated data: + +``` python +tasks = [] +printer_data = generate_data() + +# Distribute all printers over the data length +delay_seconds = int(os.environ['datalength']) / replay_speed / number_of_printers + +for i in range(number_of_printers): + # Set stream ID or leave parameters empty to get stream ID generated. + name = f"Printer {i + 1}" # We don't want a Printer 0, so start at 1 + + # Start sending data, each printer will start with some delay after the previous one + tasks.append(asyncio.create_task(generate_data_and_close_stream_async(topic_producer, name, printer_data.copy(), delay_seconds * i))) + +await asyncio.gather(*tasks) +``` + +Feel free to explore the code further. + +## πŸƒβ€β™€οΈ Next step + +[Part 3 - Downsampling service :material-arrow-right-circle:{ align=right }](./downsampling.md) diff --git a/docs/tutorials/predictive-maintenance/downsampling.md b/docs/tutorials/predictive-maintenance/downsampling.md new file mode 100644 index 00000000..9e4ea8d5 --- /dev/null +++ b/docs/tutorials/predictive-maintenance/downsampling.md @@ -0,0 +1,53 @@ +# Downsampling + +This service reduces the sampling rate of data from one per second to one per minute. + +![Downsampling pipeline segment](./images/downsampling-pipeline-segment.png) + +The service uses a buffer to buffer data for one minute before releasing. + +``` python +# buffer 1 minute of data +buffer_configuration = qx.TimeseriesBufferConfiguration() +buffer_configuration.time_span_in_milliseconds = 1 * 60 * 1000 +``` + +During the buffering the data is aggregated in the dataframe handler: + +``` python +def on_dataframe_received_handler(originating_stream: qx.StreamConsumer, df: pd.DataFrame): + if originating_stream.properties.name is not None and stream_producer.properties.name is None: + stream_producer.properties.name = originating_stream.properties.name + "-down-sampled" + + # Identify numeric and string columns + numeric_columns = [col for col in df.columns if not col.startswith('TAG__') and + col not in ['time', 'timestamp', 'original_timestamp', 'date_time']] + string_columns = [col for col in df.columns if col.startswith('TAG__')] + + # Create an aggregation dictionary for numeric columns + numeric_aggregation = {col: 'mean' for col in numeric_columns} + + # Create an aggregation dictionary for string columns (keeping the last value) + string_aggregation = {col: 'last' for col in string_columns} + + # Merge the two aggregation dictionaries + aggregation_dict = {**numeric_aggregation, **string_aggregation} + + df["timestamp"] = pd.to_datetime(df["timestamp"]) + + # resample and get the mean of the input data + df = df.set_index("timestamp").resample('1min').agg(aggregation_dict).reset_index() + + # Send filtered data to output topic + stream_producer.timeseries.buffer.publish(df) +``` + +You can read more about using buffers in the [buffer documentation](https://quix.io/docs/quix-streams/v0-5-stable/subscribe.html#using-a-buffer). + +The aggregated data is published to the output stream (one stream for each printer). + +The output topic for the service is `downsampled-3d-printer-data`. Other services such as the Forecast service, and the InfluxDB raw data storage service subscribe to this topic. + +## πŸƒβ€β™€οΈ Next step + +[Part 4 - Forecast service :material-arrow-right-circle:{ align=right }](./forecast-service.md) diff --git a/docs/tutorials/predictive-maintenance/forecast-service.md b/docs/tutorials/predictive-maintenance/forecast-service.md new file mode 100644 index 00000000..fc960137 --- /dev/null +++ b/docs/tutorials/predictive-maintenance/forecast-service.md @@ -0,0 +1,68 @@ +# Forecast service + +Generates a forecast for the temperature data received from the input topic. This is to predict a potential failure condition, when the ambient temperature of the 3D printer drops below the minimum threshold for successful ABS-based printing. + +![Forecast pipeline segment](./images/forecast-pipeline-segment.png) + +The forecast is made using the downsampled data as the input, and using the scikit-learn library. The forecasts are published to the `forecast` topic. The Alert service and Printers dashboard service both subscribe to this topic. + +## Data format + +The forecast data format is: + +```json +{ + "Epoch": 0, + "Timestamps": [ + 1701284880000000000, + 1701284940000000000, + 1701285000000000000, + ... + 1701313620000000000 + ], + "NumericValues": { + "forecast_fluctuated_ambient_temperature": [ + 42.35418149532191, + 42.43955555085827, + 42.52524883234062, + ... + 119.79365961797913 + ] + }, + "StringValues": {}, + "BinaryValues": {}, + "TagValues": { + "printer": [ + "Printer 19-down-sampled", + "Printer 19-down-sampled", + "Printer 19-down-sampled", + ... + "Printer 19-down-sampled" + ] + } +} +``` + +## Prediction algorithm + +The work of the prediction is carried out by the `scikit-learn` library, using a quadratic polynomial (second order) linear regression algorithm: + +``` python +forecast_input = df[parameter_name] + +# Define the degree of the polynomial regression model +degree = 2 +# Create a polynomial regression model +model = make_pipeline(PolynomialFeatures(degree), LinearRegression()) +# Fit the model to the data +model.fit(np.array(range(len(forecast_input))).reshape(-1, 1), forecast_input) +# Forecast the future values +forecast_array = np.array(range(len(forecast_input), len(forecast_input) + forecast_length)).reshape(-1, 1) +forecast_values = model.predict(forecast_array) +# Create a DataFrame for the forecast +fcast = pd.DataFrame(forecast_values, columns=[forecast_label]) +``` + +## πŸƒβ€β™€οΈ Next step + +[Part 5 - Alert service :material-arrow-right-circle:{ align=right }](./alert-service.md) diff --git a/docs/tutorials/predictive-maintenance/get-project.md b/docs/tutorials/predictive-maintenance/get-project.md new file mode 100644 index 00000000..f8dc5b52 --- /dev/null +++ b/docs/tutorials/predictive-maintenance/get-project.md @@ -0,0 +1,154 @@ +# Get the project + +While you can see the [deployed project running in Quix](https://portal.platform.quix.io/pipeline?token=pat-7381f57aaee34adf95382c3a60df6306&workspace=demo-predictivemaintenance-production){target=_blank}, it can be useful to learn how to get a project up and running in your own Quix account. + +Once you have the project running in your Quix account, you can modify the project as required, and save your changes to your forked copy of the project. + +With a forked copy of the repository, you can also receive upstream bug fixes and improvements if you want to, by syncing the fork with the upstream repository. + +In the following sections you learn how to: + +1. Fork an existing project repository, in this case the computer vision template project. +2. Create a new project (and environment) in Quix, linked to your forked repository. + +In later parts of the tutorial you explore the project pipeline using the Quix data explorer and other tools, in order to view code, examine data structures, and get a practical feel for Quix. + +## πŸ’‘ Key ideas + +The key ideas on this page: + +* Forking a public template project repository +* Connecting Quix to an external Git repository, in this case the forked repository +* Quix projects, environments, and applications +* Pipeline view of project +* Synchronizing an environment + +## Watch a video + +This video shows you how to fork a template project and create your project in Quix: + +
+ +Note, this is for another template project, but the process is the same. + +## Fork the project repository + +Quix provides the Clickstream template project as a [public GitHub repository](https://github.com/quixio/template-predictive-maintenance){target="_blank"}. If you want to use this template as a starting point for your own project, then the best way to accomplish this is to fork the project. Using fork enables you to create a complete copy of the project, but also benefit from future bug fixes and improvements by using the upstream changes. + +To fork the repository: + +1. Navigate to the [Quix GitHub repository](https://github.com/quixio/template-predictive-maintenance){target="_blank"}. + +2. Click the `Fork` button to fork the repo into your GitHub account (or equivalent Git provider if you don't have a GitHub account). + + !!! important + + With this repository, by default the `tutorial` branch is selected for you when you fork. If not, make sure you deselect the `fork main only` checkbox, so you fork all branches, as in this tutorial you will be working with the `tutorial` branch. + +!!! tip + + If you don't have GitHub account you can use another Git provider, such as GitLab or Bitbucket. If using Bitbucket, for example, you could import the repository - this would act as a clone (a static snapshot) of the repository. This is a simple option for Bitbucket, but you would not receive upstream changes from the original repository once the repository has been imported. You would however have a copy of the project you could then modify to suit your use case. Other providers support other options, check the documentation for your Git provider. + +## Create your Quix project + +Now that you have a forked copy of the repository in your GitHub account, you can now link your Quix account to it. Doing this enables you to build and deploy the project in your Quix account, and examine the pipeline much more closely. + +To link Quix to this forked repository: + +1. Log into your Quix account. + +2. Click `+ Create project`. + +3. Give your project a name. For example, "3D Printers". + +4. Select `Connect to your own Git repo`, and follow the setup guide for your provider. + + !!! tip + + A setup guide is provided for each of the common Git providers. Other Git providers are supported, as long as they support SSH keys. + + The setup guide for GitHub is shown here: + + ![Git seup guide](../../images/git-setup-guide.png) + +5. Assuming you are connecting to a GitHub account, you'll now need to copy the SSH key provided by Quix into your GitHub account. See the setup guide for further details. + + !!! important + + It is recommended that you create a new user in your Git provider for managing your Quix projects. You are reminded of this when you create a project (the notice is shown in the following screenshot). + + ![Create new user](../../images/create-new-github-user.png) + + +6. Click `Validate` to test the connection between Quix and GitHub. + + !!! tip + + If errors occur you need to address them before continuing. For example, make sure you have the correct link to the repository, and you have have added the provided SSH key to your provider account, as outlined in the setup guide for that provider. + +7. Click `Done` to proceed. + +You now need to add an environment to your project. This is explained in the following section. + +## Create your environment + +A Quix project contains at least one branch. For the purposes of this tutorial you will examine the `tutorial` branch of the project. In a Quix project a branch is encapsulated in an environment. You'll create a `Tutorial` environment mapped to the `tutorial` branch of the repository. + +Now create an environment called `Tutorial` which uses the `tutorial` branch: + +1. Enter the environment name `Tutorial`. + +2. Select the `tutorial` branch from the dropdown. + +3. Click `Continue` and then select the Quix Broker and Standard storage options to complete creation of the environment, and the project. + +4. Go to the pipeline view. You will see that Quix is out of sync with the repository. + +5. Click the `Sync` button to synchronize the environment, and then click `Go to pipeline`. You will see the pipeline building. + +At this point you can wait a few minutes for the pipeline services to completely build and start running. You'll see that some services are restarting, and if you check the logs you'll see that certain credentials are required for those services. In particular, access to InfluxDB is required, and the printers dashboard requires a [PAT](../../develop/authentication/personal-access-token.md) too. Stop the services that aren't starting correctly (you may found these services are stopped by default until configured correctly), and then configure the credentials as described in the next section. + +## Configure credentials + +You'll need to configure the following credentials for each Quix service that needs them: + +| Environment Variable (secret) | Service(s) | Description| +|---|---|---| +| `INFLUXDB_DATABASE` | InfluxDB raw data, InfluxDB alerts | Database name in InfluxDB where data should be stored. | +| `INFLUXDB_HOST` | InfluxDB raw data, InfluxDB alerts | Host address for the InfluxDB instance. Default: `eu-central-1-1.aws.cloud2.influxdata.com`. | +| `INFLUXDB_ORG` | InfluxDB raw data, InfluxDB alerts | Organization name in InfluxDB. | +| `INFLUXDB_TOKEN` | InfluxDB raw data, InfluxDB alerts | Authentication token to access InfluxDB. | +| `bearer_token` | Printers dashboard | A [PAT](../../develop/authentication/personal-access-token.md) that the web app uses to authenticate the Streaming Reader and Streaming Writer APIs. | + +The above is a list of environment variables that are configured as secrets (rather than, for example, free text variables). After you've forked your project, you will see a "missing secret" error for each environment variable that does not have its secret value configured. + +You need to [create secrets](../../deploy/secrets-management.md) for these and then assign them to the corresponding [environment variables](../../deploy/environment-variables.md). + +To create the secrets: + +1. Click on Settings in the botton left-hand corner of the Quix UI. + +2. Scroll down to the bottom of the screen and click on `Secrets management`. + +3. In the `Secrets management` dialog, click `+ New secret` and use this to create the following secrets (key value pairs) based on your InfluxDB account: + + * `INFLUXDB_DATABASE` + * `INFLUXDB_HOST` + * `INFLUXDB_ORG` + * `INFLUXDB_TOKEN` + +4. Also create a secret for `bearer_token` - the value will be a PAT. You can learn how to generate a PAT [here](../../develop/authentication/personal-access-token.md). + +These secrets are then automatically assigned to their corresponding environment variables. + +If you have named your secrets slightly differently to the environment variable names, you can still assign the secrets to environment variables by using the dropdown in the Deployment dialog: + +![Secrets dropdown](./images/assign-secret-dropdown.png)assign + +!!! note + + You will need to restart services (if they are running) where you have just added a secret. + +## πŸƒβ€β™€οΈ Next step + +[Part 2 - Data generator service :material-arrow-right-circle:{ align=right }](./data-generator.md) diff --git a/docs/tutorials/predictive-maintenance/images/alert-pipeline-segment.png b/docs/tutorials/predictive-maintenance/images/alert-pipeline-segment.png new file mode 100644 index 00000000..e143905a Binary files /dev/null and b/docs/tutorials/predictive-maintenance/images/alert-pipeline-segment.png differ diff --git a/docs/tutorials/predictive-maintenance/images/alert-service-logging.png b/docs/tutorials/predictive-maintenance/images/alert-service-logging.png new file mode 100644 index 00000000..a8e34be8 Binary files /dev/null and b/docs/tutorials/predictive-maintenance/images/alert-service-logging.png differ diff --git a/docs/tutorials/predictive-maintenance/images/alerts-display.png b/docs/tutorials/predictive-maintenance/images/alerts-display.png new file mode 100644 index 00000000..d59b681d Binary files /dev/null and b/docs/tutorials/predictive-maintenance/images/alerts-display.png differ diff --git a/docs/tutorials/predictive-maintenance/images/assign-secret-dropdown.png b/docs/tutorials/predictive-maintenance/images/assign-secret-dropdown.png new file mode 100644 index 00000000..cec616e4 Binary files /dev/null and b/docs/tutorials/predictive-maintenance/images/assign-secret-dropdown.png differ diff --git a/docs/tutorials/predictive-maintenance/images/data-generator-deployment-code-view.png b/docs/tutorials/predictive-maintenance/images/data-generator-deployment-code-view.png new file mode 100644 index 00000000..8e468abf Binary files /dev/null and b/docs/tutorials/predictive-maintenance/images/data-generator-deployment-code-view.png differ diff --git a/docs/tutorials/predictive-maintenance/images/data-generator-pipeline-segment.png b/docs/tutorials/predictive-maintenance/images/data-generator-pipeline-segment.png new file mode 100644 index 00000000..5c4015d6 Binary files /dev/null and b/docs/tutorials/predictive-maintenance/images/data-generator-pipeline-segment.png differ diff --git a/docs/tutorials/predictive-maintenance/images/downsampling-pipeline-segment.png b/docs/tutorials/predictive-maintenance/images/downsampling-pipeline-segment.png new file mode 100644 index 00000000..2fd7257d Binary files /dev/null and b/docs/tutorials/predictive-maintenance/images/downsampling-pipeline-segment.png differ diff --git a/docs/tutorials/predictive-maintenance/images/forecast-pipeline-segment.png b/docs/tutorials/predictive-maintenance/images/forecast-pipeline-segment.png new file mode 100644 index 00000000..09383b74 Binary files /dev/null and b/docs/tutorials/predictive-maintenance/images/forecast-pipeline-segment.png differ diff --git a/docs/tutorials/predictive-maintenance/images/influxdb-alerts-pipeline-segment.png b/docs/tutorials/predictive-maintenance/images/influxdb-alerts-pipeline-segment.png new file mode 100644 index 00000000..9d12cbf8 Binary files /dev/null and b/docs/tutorials/predictive-maintenance/images/influxdb-alerts-pipeline-segment.png differ diff --git a/docs/tutorials/predictive-maintenance/images/influxdb-raw-data-pipeline-segment.png b/docs/tutorials/predictive-maintenance/images/influxdb-raw-data-pipeline-segment.png new file mode 100644 index 00000000..a0da44ff Binary files /dev/null and b/docs/tutorials/predictive-maintenance/images/influxdb-raw-data-pipeline-segment.png differ diff --git a/docs/tutorials/predictive-maintenance/images/influxdb_alerts.png b/docs/tutorials/predictive-maintenance/images/influxdb_alerts.png new file mode 100644 index 00000000..c81feb89 Binary files /dev/null and b/docs/tutorials/predictive-maintenance/images/influxdb_alerts.png differ diff --git a/docs/tutorials/predictive-maintenance/images/influxdb_data.png b/docs/tutorials/predictive-maintenance/images/influxdb_data.png new file mode 100644 index 00000000..5f519f3f Binary files /dev/null and b/docs/tutorials/predictive-maintenance/images/influxdb_data.png differ diff --git a/docs/tutorials/predictive-maintenance/images/library-pushover.png b/docs/tutorials/predictive-maintenance/images/library-pushover.png new file mode 100644 index 00000000..35ab4799 Binary files /dev/null and b/docs/tutorials/predictive-maintenance/images/library-pushover.png differ diff --git a/docs/tutorials/predictive-maintenance/images/merge-request-menu.png b/docs/tutorials/predictive-maintenance/images/merge-request-menu.png new file mode 100644 index 00000000..7a09f544 Binary files /dev/null and b/docs/tutorials/predictive-maintenance/images/merge-request-menu.png differ diff --git a/docs/tutorials/predictive-maintenance/images/message-format.png b/docs/tutorials/predictive-maintenance/images/message-format.png new file mode 100644 index 00000000..f3d9d99c Binary files /dev/null and b/docs/tutorials/predictive-maintenance/images/message-format.png differ diff --git a/docs/tutorials/predictive-maintenance/images/messages-topic-dropdown.png b/docs/tutorials/predictive-maintenance/images/messages-topic-dropdown.png new file mode 100644 index 00000000..37a284c9 Binary files /dev/null and b/docs/tutorials/predictive-maintenance/images/messages-topic-dropdown.png differ diff --git a/docs/tutorials/predictive-maintenance/images/new-environment.png b/docs/tutorials/predictive-maintenance/images/new-environment.png new file mode 100644 index 00000000..b5a61519 Binary files /dev/null and b/docs/tutorials/predictive-maintenance/images/new-environment.png differ diff --git a/docs/tutorials/predictive-maintenance/images/predictive-maintenance-pipeline.png b/docs/tutorials/predictive-maintenance/images/predictive-maintenance-pipeline.png new file mode 100644 index 00000000..17a2a02f Binary files /dev/null and b/docs/tutorials/predictive-maintenance/images/predictive-maintenance-pipeline.png differ diff --git a/docs/tutorials/predictive-maintenance/images/printers-dashboard-pipeline-segment.png b/docs/tutorials/predictive-maintenance/images/printers-dashboard-pipeline-segment.png new file mode 100644 index 00000000..c6cda72f Binary files /dev/null and b/docs/tutorials/predictive-maintenance/images/printers-dashboard-pipeline-segment.png differ diff --git a/docs/tutorials/predictive-maintenance/images/printers-dashboard.png b/docs/tutorials/predictive-maintenance/images/printers-dashboard.png new file mode 100644 index 00000000..d54249c3 Binary files /dev/null and b/docs/tutorials/predictive-maintenance/images/printers-dashboard.png differ diff --git a/docs/tutorials/predictive-maintenance/images/pushover-notification.png b/docs/tutorials/predictive-maintenance/images/pushover-notification.png new file mode 100644 index 00000000..5f666f8f Binary files /dev/null and b/docs/tutorials/predictive-maintenance/images/pushover-notification.png differ diff --git a/docs/tutorials/predictive-maintenance/images/squash-and-merge.png b/docs/tutorials/predictive-maintenance/images/squash-and-merge.png new file mode 100644 index 00000000..be8ac05e Binary files /dev/null and b/docs/tutorials/predictive-maintenance/images/squash-and-merge.png differ diff --git a/docs/tutorials/predictive-maintenance/images/success-pushover.png b/docs/tutorials/predictive-maintenance/images/success-pushover.png new file mode 100644 index 00000000..af90d18b Binary files /dev/null and b/docs/tutorials/predictive-maintenance/images/success-pushover.png differ diff --git a/docs/tutorials/predictive-maintenance/images/sync-environment.png b/docs/tutorials/predictive-maintenance/images/sync-environment.png new file mode 100644 index 00000000..9a460097 Binary files /dev/null and b/docs/tutorials/predictive-maintenance/images/sync-environment.png differ diff --git a/docs/tutorials/predictive-maintenance/influxdb-alerts.md b/docs/tutorials/predictive-maintenance/influxdb-alerts.md new file mode 100644 index 00000000..acd808f4 --- /dev/null +++ b/docs/tutorials/predictive-maintenance/influxdb-alerts.md @@ -0,0 +1,20 @@ +# InfluxDB - alerts + +This service uses the standard Quix InfluxDB 3.0 [connector](../../connectors/index.md). This connector enables the service to subscribe to messages on a Quix topic to be stored in InfluxDB. + +![InfluxDB raw data pipeline segment](./images/influxdb-alerts-pipeline-segment.png) + +In this pipeline the connector subscribes to the `alerts` topic, and writes these messages into InfluxDB for permanent storage. + + +## Query the data in InfluxDB + +Log into your InfluxDB account. Go to the data explorer, select the Measurement `Alerts`, and then construct a query to examine the data being stored in your database. For example: + +![InfluxDB - Data](./images/influxdb_alerts.png) + +Explore the table of data to ensure you are familiar with the data stored. + +## πŸƒβ€β™€οΈ Next step + +[Part 8 - Printers dashboard :material-arrow-right-circle:{ align=right }](./printers-dashboard.md) diff --git a/docs/tutorials/predictive-maintenance/influxdb-raw-data.md b/docs/tutorials/predictive-maintenance/influxdb-raw-data.md new file mode 100644 index 00000000..b9ed9c8c --- /dev/null +++ b/docs/tutorials/predictive-maintenance/influxdb-raw-data.md @@ -0,0 +1,19 @@ +# InfluxDB - raw data + +This service uses the standard Quix InfluxDB 3.0 [connector](../../connectors/index.md). This connector enables the service to subscribe to messages on a Quix topic to be stored in InfluxDB. + +![InfluxDB raw data pipeline segment](./images/influxdb-raw-data-pipeline-segment.png) + +In this pipeline the connector subscribes to the `downsampled-3d-printer-data` topic, and writes these messages into InfluxDB for permanent storage. + +## Query the data in InfluxDB + +Log into your InfluxDB account. Go to the data explorer, select the Measurement `Data`, and then construct a query to examine the data being stored in your database. For example: + +![InfluxDB - Data](./images/influxdb_data.png) + +Explore the table of data to ensure you are familiar with the data stored. + +## πŸƒβ€β™€οΈ Next step + +[Part 7 - InfluxDB alerts service :material-arrow-right-circle:{ align=right }](./influxdb-alerts.md) diff --git a/docs/tutorials/predictive-maintenance/overview.md b/docs/tutorials/predictive-maintenance/overview.md new file mode 100644 index 00000000..3d5014ce --- /dev/null +++ b/docs/tutorials/predictive-maintenance/overview.md @@ -0,0 +1,127 @@ +# Predictive maintenance + +In this tutorial you learn about a project template that demonstrates real-time predictive analytics. It simulates three temperature sensors on a fleet of 3D printers. It predicts temperature for the printers using the `scikit-learn` library. + +This tutorial uses the [Quix predictive maintenance template project](https://github.com/quixio/template-predictive-maintenance){target=_blank}. + +![Predictive maintenance pipeline](./images/predictive-maintenance-pipeline.png) + +You'll fork the complete project from GitHub, and then create a Quix project from the forked repo, so you have a copy of the full application code running in your Quix account. You then examine the data flow through the project's pipeline, using tools provided by Quix. + +
+See the project running in Quix + +See the deployed project + +
+
+ +## Technologies used + +Some of the technologies used by this template project are listed here. + +**Infrastructure:** + +* [Quix](https://quix.io/){target=_blank} +* [Docker](https://www.docker.com/){target=_blank} +* [Kubernetes](https://kubernetes.io/){target=_blank} + +**Backend:** + +* [Aiven Kafka](https://aiven.io/kafka){target=_blank} +* [Quix Streams](https://github.com/quixio/quix-streams){target=_blank} +* [scikit-learn](https://scikit-learn.org/stable/){target=_blank} +* [InfluxDB](https://www.influxdata.com/products/influxdb-cloud/serverless/){target=_blank} + +**Frontend:** + +* [Angular](https://angular.io/){target=_blank} +* [Typescript](https://www.typescriptlang.org/){target=_blank} +* [Microsoft SignalR](https://learn.microsoft.com/en-us/aspnet/signalr/){target=_blank} + +## GitHub repository + +The complete code for this project can be found in the [Quix GitHub repository](https://github.com/quixio/template-predictive-maintenance){target="_blank"}. + +## Getting help + +If you need any assistance while following the tutorial, we're here to help in the [Quix Community](https://quix.io/slack-invite){target="_blank"}. + +## Prerequisites + +To get started make sure you have a [free Quix account](https://portal.platform.quix.ai/self-sign-up){target="_blank"}. + +### InfluxDB + +You'll need a [free InfluxDB](https://www.influxdata.com/products/influxdb-cloud/serverless/){target=_blank} account to try this out in your Quix account. + +### Pushover + +If you want to implement the optional lab task to add phone alerts to your pipeline, you will need to sign up for a free [Pushover](https://pushover.net/signup){target=_blank} account. + +Enter your details, and click `Signup`. You will receive a welcome email, and you can log in to Pushover to retrieve your user key and generate an API token. + +This enables you to send notifications to your phone. + +Install the Pushover mobile app from the [Apple App store](https://apps.apple.com/us/app/pushover-notifications/id506088175){target=_blank} or [Google Play](https://play.google.com/store/apps/details?id=net.superblock.pushover&hl=en){target=_blank}. + +### Git provider + +You also need to have a Git account. This could be GitHub, Bitbucket, GitLab, or any other Git provider you are familar with, and that supports SSH keys. The simplest option is to create a free [GitHub account](){target=_blank}. + +!!! tip + + While this tutorial uses an external Git account, Quix can also provide a Quix-hosted Git solution using Gitea for your own projects. You can watch a video on [how to create a project using Quix-hosted Git](https://www.loom.com/share/b4488be244834333aec56e1a35faf4db?sid=a9aa124a-a2b0-45f1-a756-11b4395d0efc){target=_blank}. + +## The pipeline + +There are several *main* stages in the [pipeline](https://portal.platform.quix.io/pipeline?token=pat-7381f57aaee34adf95382c3a60df6306&workspace=demo-predictivemaintenance-production){target=_blank}: + +1. *Data generator* - generates the temperature data for a fleet of 3D printers. +2. *Downsampling* - downsamples data from one second to one minute. +3. *Forecast* - uses the `scikit-learn`library to predict 3D printer temperature. +4. *Alerts* - triggers alerts if thresholds are exceeded for current temperature data, and forecast data. +5. *InfluxDB - raw data* - writes the downsampled data to InfluxDB for permanent storage. +6. *InfluxDB - alerts* - writes the alert messages to InfluxDB for permanent storage. +7. *Printers dashboard* - dipslays the temperature data for the specified data, including predicted ambient (enclosure) temperature. + +More details are provided on all these services later in the tutorial. + +## Topics + +The following Kafka topics are present in the project: + +| Topic | Description | Producer service | Consumer service(s) +|---|---|---|---| +| `3d-printer-data` | The generated 3D printer temperature data | Data generator | Downsampling, Printers dahsboard | +| `downsampled-3d-printer-data` | Down samples the data from 1 second to 1 minute | Downsampling | Forecast, InfluxDB raw data | +| `forecast` | Forecast temperature | Forecast | Alert, Printers dashboard | +| `alerts` | Temperature alert | Alert | Printers dashboard, InfluxDB alerts | + +## The parts of the tutorial + +This tutorial is divided up into several parts, to make it a more manageable learning experience. The parts are summarized here: + +1. [Get the project](get-project.md) - you get the project up and running in your Quix account. + +2. [Data generator](./data-generator.md) - you explore the data generator service, including generated message format and application code. + +3. [Downsampling](./downsampling.md) - you see how data is downsampled from 1 second to 1 minute using buffering and aggregation. + +4. [Forecast](./forecast-service.md) - you learn that the `scikit-learn` library is used to make a prediction of ambient temperature using a linear regression algorithm. + +5. [Alerts](./alert-service.md) - you learn how this service generates alerts based on thresholds held in environment variables. + +6. [InfluxDB - raw data](./influxdb-raw-data.md) - you see how InfluxDB is used to permanently store downsampled printer temperature data. + +7. [InfluxDB - alerts](./influxdb-alerts.md) - you see how InfluxDB is used to permanently store alert messages. + +8. [Printers dashboard](./printers-dashboard.md) - you learn how Streaming Reader API can enable your web app to subscribe to messages published to Quix topics. + +9. [Lab: add phone alerts](./phone-alerts.md) - you add a phone alerts service to your pipeline, using the Pushover service, and the Quix ready-to-use Pushover connector. + +10. [Summary](summary.md) - in this concluding part you are presented with a summary of the work you have completed, and also some next steps for more advanced learning about Quix. + +## πŸƒβ€β™€οΈ Next step + +[Part 1 - Get the project :material-arrow-right-circle:{ align=right }](get-project.md) diff --git a/docs/tutorials/predictive-maintenance/phone-alerts.md b/docs/tutorials/predictive-maintenance/phone-alerts.md new file mode 100644 index 00000000..c5046dd0 --- /dev/null +++ b/docs/tutorials/predictive-maintenance/phone-alerts.md @@ -0,0 +1,217 @@ +# πŸ‘©β€πŸ”¬ Lab: add phone alerts + +In this lab you use what you've learned so far, to add a new service, that can send alerts to your phone. + +You develop this change on a feature branch, and then you create a PR to merge your new feature into the `tutorial` branch after testing. + +This is a common pattern for development - you can test your new service on the feature branch, and then test again, before final integration into the production `main` branch. + +## Create an environment + +To create a new environment (and branch): + +1. Click `+ New environment` to create a new environment (note, your screen will look slightly different to the one shown here): + + ![New environment](./images/new-environment.png) + +2. Create a new environment called `Phone Alert`. + +3. Create a new branch called `phone-alert`. To do this, from the branch dropdown click `+ New branch` which displays the New branch dialog. + + !!! important + + Make sure you branch from the `tutorial` branch, not `main`, as you are going to merge your changes back to the `tutorial` branch. + +4. Complete creation of the environment using the default options. + +5. On the projects screen, click your newly created environment, `Phone Alert`. + +## Sync the environment + +You now see that the Quix environment is out of sync with the Git repository. You need to synchronize the Quix view of the environment, with that stored in the repository. + +To synchronize Quix with the repository: + +1. Click `Sync environment`: + + ![Sync environment](./images/sync-environment.png) + + The sync environment dialog is displayed, showing you the changes that are to be made to the `quix.yaml` file, which is the configuration file that defines the pipeline. + +2. Click `Sync environment`, and then `Go to pipeline`. + + In the pipeline view, you see the services building. Ensure all services are "Running" before continuing. + +## Add an alert filter tranformation service + +It would not be a good thing if your phone was alerting you for every alert produced by the alert service. For this reason, this service is used to filter alerts to only publish the ambient forecast over temperature alert. That is the alert produced when the ambient temperature goes above a safe level. + +To add a filter transformation service: + +1. Click on the `Code Samples` icon in the left-hand navigation. + +2. Select `Transformation` and `Basic Templates`, then click `Starter transformation`. + +3. Click `Edit code`, and set the `Application name` to `Alerts Filter`, and click `Save`. + +You'll now edit the code to implement the functionality you require. + +Modify your input topic to be `alerts`, and the output topic to be a new topic `ambient-alerts` (you'll need to use the `New topic` button to create this). + +You're only interested in forecast over temperature alerts, which have the message format: + +``` json +[ + { + "Timestamp": 1701348695725335000, + "Tags": { + "TAG__printer": "Printer 11-down-sampled - Forecast" + }, + "Id": "over-forecast", + "Value": "{\"status\": \"over-forecast\", \"parameter_name\": \"forecast_fluctuated_ambient_temperature\", \"alert_temperature\": 55.00501762733715, \"alert_timestamp\": 1.70137236e+18, \"message\": \"'Ambient temperature' is forecasted to go over 55\\u00baC in 6:34:24.\"}" + } +] +``` + +So you are looking for an `Id` of `over-forecast`. + +You only want to publish the alert message to the output topic if it has the correct ID. Modify the event handler to the following: + +``` python +def on_event_data_received_handler(stream_consumer: qx.StreamConsumer, data: qx.EventData): + if data.id == 'over-forecast': + print(data) + stream_producer = topic_producer.get_or_create_stream(stream_id = stream_consumer.stream_id) + stream_producer.events.publish(data) +``` + +Commit your changes. + +### Test the service + +Now that you've modified the code, you'll now test your changes: + +1. Tag your changes, for example as `alerts-filter-v1`. + +2. Click the `Deploy` button and select your changed version from the `Version tag` dropdown. + +3. Once the `Alerts Filter` service is running, you are ready to proceed to the next step. + +## Add the Pushover destination + +In this section you create a destination service that sends a push notification to your phone when an alert condition occurs. + +This service subscribes to the `ambient-alerts` topic and whenever a new message arrives, it sends a push notification to the Pushover app on your mobile phone. + +To set up the push notification service, follow these steps: + +1. Click on the `Code Samples` icon in the left-hand navigation. + +2. In the search box on the Code Samples page, enter "Pushover". + + You will see the `Pushover Output` sample appear in the search results: + + ![Pushover Notifications](./images/library-pushover.png "Pushover Notifications") + +3. Click the `Preview code` button, and on the page that appears, click the `Edit code` button. + +4. On the `Setup application` page, complete the following fields: + + | Field | Value | + | --- | --- | + | `Name` | Enter an application name or keep the default suggestion. | + | `Input` | Select the input topic. In this case, select `ambient-alerts` from the list. Every message will be read from this topic, and turned into a push notification. | + | `base_url` | Leave the default value, `https://api.pushover.net/1/messages.json?`. If you decide to use another push notification app, your can always update this value. | + | `api_token` | Enter the API token that you generated for this application in your Pushover dashboard. For example: `azovmnbxxdxkj7j4g4wxxxdwf12xx4`. | + | `user_key` | Enter the user key that you received when you signed up with Pushover. For example: `u721txxxgmvuy5dxaxxxpzx5xxxx9e` | + +5. Click the `Save as Application`. You now have a copy of the Pushover notification sample in your environment. + +6. Click the `Deploy` button. + +### Test the service + +You will shortly start receiving Pushover notifications on your phone, as shown here: + +![Pushover Notification Example](./images/pushover-notification.png){width=60%} + +If you want to change the message received you can edit the `quix_function.py` code in the Pushover destination: + +``` python +# Callback triggered for each new event +def on_event_data_handler(self, stream_consumer: qx.StreamConsumer, data: qx.EventData): + print(data) + + # send your push message + try: + pushmsg = {'token': self.apitoken, + 'user': self.userkey, + 'message': 'An event has been detected'} + requests.post(self.baseurl, json = pushmsg) + except Exception as e: + print(f"Error connecting to push API: {e}") +``` + +Change "An event has been detected" to anything you like. + +!!! note + + In Pushover this application was named "3D Printers". + +Depending on the stage of the printing cycle, it might take a few minutes for you to get a notification. While you are waiting to receive a notification, you can inspect the logs, as shown previously. + +![Pushover Logs](./images/success-pushover.png) + +* Don't worry if the logs only show "_Listening to Stream_" initially β€” remember that the Alert Filter service only writes a message to the `ambient-alerts` topic when the ambient predicted temperature is over the threshold. +* This means that the `ambient-alerts` stream might be empty for a short while, until a threshold is triggered. + +## Merge the feature + +Once you are sure that the changes on your feature branch are tested, you can then merge your changes onto the `tutorial` branch. Here your changes undergo further tests before finally being merged into production. + +To merge your feature branch, `phone-alert` into `tutorial`: + +1. Select `Merge request` from the menu as shown: + + ![Merge request menu](./images/merge-request-menu.png) + +2. In the `Merge request` dialog, set the `phone-alert` branch to merge into the `tutorial` branch. + +You are going to create a pull request, rather than perform a direct merge. This enables you to have the PR reviewed in GitHub (or other Git provider). You are also going to do a squash and merge, as much of the feature branch history is not required. + +To create the pull request: + +1. Click `Create pull request`. You are taken to your Git provider, in this case GitHub. + +2. Click the `Pull request` button. + +3. Add your description, and then click `Create pull request`. + +4. Get your PR reviewed and approved. Then squash and merge the commits: + + ![Squash and merge](./images/squash-and-merge.png) + + You can replace the prefilled description by something more succinct. Then click `Confirm squash and merge`. + + !!! tip + + You can just merge, you don't have to squash and merge. You would then retain the complete commit history for your service while it was being developed. Squash and merge is used in this case by way of example, as the commit messages generated while the service was being developed were deemed to be not useful in this case. + +## Resync the environment + +You have now merged your new service into the `tutorial` branch in the Git repository. Your Quix view in the Tutorial environment is now out of sync with the Git repository. If you click on your Tutorial environment in Quix, you'll see it is now a commit (the merge commit) behind. + +You now need to make sure your Tutorial environment in Quix is synchronized with the Git repository. To do this: + +1. Click on `Sync environment`. The `Sync environment` dialog is displayed. + +2. Review the changes and click `Sync environment`. + +3. Click `Go to pipeline`. + +Your new service builds and starts in the Tutorial environment, where you can now carry out further testing. When you are satisfied this feature can be released to production, you would then repeat the previous process to merge your changes to Production `main`. + +## πŸƒβ€β™€οΈ Next step + +[Part 10 - Summary :material-arrow-right-circle:{ align=right }](summary.md) + diff --git a/docs/tutorials/predictive-maintenance/printers-dashboard.md b/docs/tutorials/predictive-maintenance/printers-dashboard.md new file mode 100644 index 00000000..8f09b613 --- /dev/null +++ b/docs/tutorials/predictive-maintenance/printers-dashboard.md @@ -0,0 +1,21 @@ +# Printers dashboard + +The printers dashboard service is a web app that displays the temperature of the selected printer in real time: + +![Printers dashboard](./images/printers-dashboard.png) + +The Quix [Streaming Reader API](../../apis/streaming-reader-api/overview.md) is used to subscribe to several topics, to read data into the web app. + +The topics subscribed to are: + +* `alerts` +* `forecast` +* `3d-printer-data` + +![Printers dashboard pipeline segment](./images/printers-dashboard-pipeline-segment.png) + +You can see the dashboard running [here](https://dash-demo-predictivemaintenance-production.deployments.quix.io/?_ga=2.114191879.1628320822.1701679251-1544698923.1686060578){target=_blank}. + +## πŸƒβ€β™€οΈ Next step + +[Part 9 - Lab: Add phone alert :material-arrow-right-circle:{ align=right }](./phone-alerts.md) diff --git a/docs/tutorials/predictive-maintenance/summary.md b/docs/tutorials/predictive-maintenance/summary.md new file mode 100644 index 00000000..61da5d4d --- /dev/null +++ b/docs/tutorials/predictive-maintenance/summary.md @@ -0,0 +1,25 @@ +# Summary + +In this tutorial you have learned that it is possible to quickly fork a complete Quix project and get it up and running in your Quix account very quickly. This enables you to start your own project by using one of our templates. You can then modify our code, keeping your project in a public or private Git repository as required. Alternatively, you can build your own custom pipeline from a mix of our code samples, and your own custom sources, transforms, and destinations. + +In addition, you have seen how in Quix you can: + +* See the power of navigating your pipeline visually +* View the logs of a service as an aid to debugging +* View live data in the application view, or using the Quix Data Explorer +* Learned how you can host your project in a Git repository +* Learn how to examine the raw message data in the messages view +* Examine and edit the code of a service + +## Next Steps + +Here are some suggested next steps to continue on your Quix learning journey: + +* Build something with our [Code Samples](../../develop/code-samples.md). +* Try the [Clickstream analysis tutorial](../clickstream/overview.md). +* Try the [Computer vision tutorial](../computer-vision/overview.md). +* If you decide to build your own connectors and apps, you can contribute something to the Code Samples. Visit the [GitHub Code Samples repository](https://github.com/quixio/quix-samples){target=_blank}. Fork our Code Samples repo and submit your code, updates, and ideas. + +## Get help + +If you have any further questions, we're here to help in the [Quix Community](https://quix.io/slack-invite){target="_blank"}. diff --git a/mkdocs.yml b/mkdocs.yml index e16e7716..9cee6dc2 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -105,6 +105,18 @@ nav: - 'HTTP requests': 'apis/portal-api/http-requests.md' - 'Tutorials': - 'Overview': 'tutorials/overview.md' + - 'Predictive maintenance': + - 'Overview': 'tutorials/predictive-maintenance/overview.md' + - '1. Get the project': 'tutorials/predictive-maintenance/get-project.md' + - '2. Data generator': 'tutorials/predictive-maintenance/data-generator.md' + - '3. Downsampling': 'tutorials/predictive-maintenance/downsampling.md' + - '4. Forecast': 'tutorials/predictive-maintenance/forecast-service.md' + - '5. Alerts': 'tutorials/predictive-maintenance/alert-service.md' + - '6. InfluxDB - raw data': 'tutorials/predictive-maintenance/influxdb-raw-data.md' + - '7. InfluxDB - alerts': 'tutorials/predictive-maintenance/influxdb-alerts.md' + - '8. Printers dashboard': 'tutorials/predictive-maintenance/printers-dashboard.md' + - '9. Lab: Add phone alerts': 'tutorials/predictive-maintenance/phone-alerts.md' + - '10. Summary': 'tutorials/predictive-maintenance/summary.md' - 'Clickstream analysis': - 'Overview': 'tutorials/clickstream/overview.md' - '1. Get the project': 'tutorials/clickstream/get-project.md'