Monitor Your 3d Printer With Viam Using a Raspberry Pi and LEDs

by michaellee1019 in Workshop > 3D Printing

991 Views, 9 Favorites, 0 Comments

Monitor Your 3d Printer With Viam Using a Raspberry Pi and LEDs

Screenshot 2023-09-21 at 2.15.33 PM.png

Robots in the cloud? Why not. The combination of Octoprint, AWS, and Viam make it easy and secure.

This project allows you to easily monitor the progress of your 3d print from any location, securely, while still keeping your printer's software on your local network to prevent hacking. I mount it on my monitor at both work and home to see the status of a print and take action when I need to. This project utilizes:

  • OctoPrint along with the webhooks plugin to send status events.
  • Uses an AWS API Gateway Endpoint and an AWS Lambda to receive the event.
  • Uses the Viam SDK to communicate with a robot securely where ever it is connected to the internet.
  • Uses a Raspberry Pi with the Viam RDK installed to control a 16 segment LED array.
  • Uses a Viam Modular Resource I wrote to control the LEDs.

Note: You may incur some cloud costs in the amount of cents when using this robot. The majority of AWS services used in this integration are Free Tier eligible and Viam usage under $5 per month is currently free.

Supplies

  1. 1x Rasperry Pi. Recommended to use Raspberry Pi 4 Model B (2GB) or better
  2. 2x 4 Digit 16 Segment LED HT16K33 or VK16K33 Module such as
  3. 2x SparkFun Qwiic Alphanumeric Display
  4. 1x EC Buying Segment Display Module
  5. Optional: 1x Grove I2C Hub and 1x Female Grove Jumper Cables: Personally I use the Seeed Studio Grove System to ensure a reliable electrical connection. The system is re-useable across other projects and reduces. troubleshooting time related to soldering and wiring issues.
  6. Grove also provides a Qwiic Hub if you choose to combine Qwiic and Grove components together.
  7. M2 Standoffs, Screws and Nuts for LED and Grove I2C Hub.
  8. M2.5 Standoffs, Screws and Nuts for Raspberry Pi.
  9. 1x 3D Printed Mount that I created for this project is available in OnShape.
  10. 1x Two sided 3M Tape or Command Strip.
  11. Some electrical or scotch tape.
  12. Precision Philips Screwdriver (for small screws)
  13. Adjustable C Wrench
  14. Soldering Iron and Solder

This tutorial, obviously also requires a 3D Printer with Octoprint controlling it and the webhooks plugin installed.

Imaging and Software Install

  1. Follow Viam's Raspberry Pi Imaging Instructions to image your Raspberry Pi. You can use an already existing installation if you have one, but it must be a 64bit OS.
  2. Be sure to enable I2C while following the instructions.
  3. Follow Viam's setup instructions to get Viam running on the Raspberry Pi.
  4. Install I2C tools for troubleshooting:
sudo apt-get update
sudo apt-get install i2c-tools

Display Soldering

Soldering Direction.png

Each display module will have the same I2C address by default and soldering needs to be done to make each display have a unique address. Depending on the model purchased, there should be 2 or 3 soldering points that allow 4 or 8 unique I2C addresses respectively. For example the Hardware Overview of the SparkFun Qwiic Alphanumeric Display describes the resulting address when soldering closed the contacts on the display.

In addition, for the EC Buying Segment Display: You will need to solder the pins to the display. It is recommended to solder the pins facing up when looking at the back of the board. Otherwise the pins may get in the way when mounting the device to your monitor.

Robot Wiring

RaspberryPiWiring.png
Display_Wiring.png

Follow these instructions to wire the RaspberryPi, I2C Hub, and Displays together. If you have chosen another wiring mechanism instead of using Grove connectors, skip this step and proceed with your own setup.

  1. Attach the jumper side of the cables to both displays:
  2. Yellow: SCL
  3. White: SDA
  4. Black: GND
  5. Red: VCC
  6. If your display has other pins, you can ignore them
  7. Attach the jumper side of the a 3rd cable to the RaspberryPi GPIO Pins:
  8. Yellow: GPIO 3 (SCL)
  9. White: GPIO 2 (SDA)
  10. Black: Any Ground pin
  11. Red: Any 5V power pin
  12. Connect the grove connector ends to the I2C Hub (in any order).

Viam Configuration and Testing

Within your Viam robot, you will add configuration to setup the LED displays and install a Viam Modular Resource (details on how it works can be read here) onto your robot. For this project I have developed a michaellee1019:ht16k33:seg_14_x_4 Model that supports the display within my viam-modular-resources Module.

All you have todo to use this module is add it to your robot config.

1. Navigate to the Config tab of your robot on app.viam.com. Paste the following JSON into your robot config. This adds the Module, Model, and attributes to make the model work.


{
"components": [
{
"name": "led_displays",
"model": "michaellee1019:ht16k33:seg_14_x_4",
"type": "generic",
"namespace": "rdk",
"attributes": {
"brightness": 0.05,
"addresses": [
"0x70",
"0x71"
]
},
"depends_on": []
}
],
"modules": [
{
"type": "registry",
"name": "michaellee1019_viam-modular-resources",
"module_id": "michaellee1019:viam-modular-resources",
"version": "0.0.41"
}
]
}

2. Your I2C addresses will likely vary from mine. To determine the correct addresses, run the following on your Raspberry Pi. This will output the I2C addresses of devices that are communicating with the Pi.

sudo i2cdetect -y 1

3. The command will produce an output similar to this. If you see no numbers other than the row and column headings, and everything is dashes, it means that the displays are not wired correctly. Check your wiring and keep testing with this output:

     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f

00:                         -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: 70 71 -- -- -- -- -- -- 

4. Change your configuration as appropriate. On my robot, the displays are communicating on addresses 70 and 71 so the configuration should match. Note that the order matters, the display on address 70 will show the first 4 characters and the 2nd will show the next 4 characters of the text. This can be fine tuned later:

        "addresses": [
"0x70",
"0x71"
]

5. Switch to the Control tab of your robot. Look for the DoCommand() section, pick led_displays from the components dropdown. Enter the following JSON to test the robot, resulting in the text displaying.

{"print":{"value":"HELLO123"}}

6. Here are some troubleshooting steps if no text is displayed:

a. If the DoCommand() sections is not displayed, check the Logs tab for information about why your robot is not working

b. If a red popup displays on app.viam.com, read the error message and change the configuration as appropriate.

c. If you are still having issues, double check the wiring of the robot. Also double check that I2C is enabled on your robot.

Robot Construction

RaspberryPi_Mounting.png
I2C_Hub_Mounting.png
Tape_Together.png
LED_Mounting.png
Screen_Mounting.png

Build the robot using the supplies listed. The screw holes overlap some components, so my recommended setup is:

  1. Ensure the SD card is still inserted into the Raspberry Pi (it won't be accessible once construction is done).
  2. Attach the Raspberry Pi to the 4 large holes in the 3d print. Be sure to orient it so the USB port is facing up relative to the 8 holes at the bottom used for mounting the LED Screens.
  3. There should be 3 holes to the right of the Raspberry Pi. Attach the I2C Hub using the M2 Standoffs and Screws on the same side of the board as the Raspberry Pi. The 3d print is designed so that you thread the M2 standoffs into the plastic and do not need to use nuts.
  4. Tape the displays together on the back so that you achieve a straight line of text on the display.
  5. Turn the board around and attach the two LED displays. When attaching the displays, The holes might not be in the exact spots as the display (there are a lot of different models), but the displays will remain secure without all attaching all screws. I have threaded the standoffs on all holes into the plastic, but only placed two screws.
  6. Place the two sided tape on the rectangular protrusion on the 3d print. Stick the other side to the back of your computer monitor in a flat location.

When completed you should have an LED display at the bottom of your monitor that supports eight characters. On the back of the display is a Raspberry pi and I2C hub that will control the displays. You can connect the Raspberry Pi to your monitor if a USB port exists, or to a power outlet.

AWS Prerequisites & Installation

  1. Install Docker.
  2. Create an AWS account or use an existing account where you have permissions to modify AWS Lambda, API Gateway, and Identity and Access Management.
  3. Install the AWS CLI.
  4. Authenticate your computer with the AWS CLI, usually using aws configure, or some other authentication option

Setup Robot Secrets in AWS

Screenshot 2023-09-21 at 1.05.58 PM.png

It is important to never expose your Viam secret or domain in code or other files. This project uses AWS Parameter Store, a feature within AWS Systems Manager, to store secrets in the cloud that are accessed in runtime by the lambda. The example requires two `SecureString` to be entered into Parameter Store:

  • /printerstatus/location_secret
  • /printerstatus/robot_fqdn.

On Viam's website you can copy these values on the Code Sample tab of your robot.

  • location_secret will be the value that appears in code sample when you toggle on "Include Secret"
payload='<SECRET>'
  • robot_fqdn will be the domain of the robot that is shown in the line:
return await RobotClient.at_address('<ROBOT_FQDN>', opts)

Follow these steps to populate your screts into Parameter Store:

  1. Go to parameter store in your desired aws region, for example: https://us-east-1.console.aws.amazon.com/systems-manager/parameters/?region=us-east-1
  2. Click "Create Parameter" and populate the form with these values
  3. Name: /printerstatus/location-secret/
  4. Type: SecureString
  5. KMS key source: My current account
  6. Value: Paste your location secret into this box.
  7. Click "Create Parameter"
  8. Follow the same steps to populate a /printerstatus/robot_fqdn secure string with your robot's domain.

AWS Lambda Creation

Screenshot 2023-09-21 at 1.04.04 PM.png

This step will connect all parts of the system together.

AWS Lambda Creation

  1. Login to the AWS Console: https://console.aws.amazon.com.
  2. Go to AWS Lambda
  3. Click "Create Function"
  4. Populate the Form with:
  5. Function Name: PrinterStatus
  6. Runtime: Python 3.8
  7. Architecture: x86_64
  8. Click "Create Function"

Increase AWS Lambda Timeout

Screenshot 2023-09-21 at 9.38.29 AM.png

The default timeout (3 sec) for AWS Lambda is not long enough for many robotics projects. The network traversal that is done to connect to your robot from the cloud, can take several seconds. Then, synchronous robot control will take additional time.

Change your Lambda Function's timeout to 30 seconds by following these steps:

  1. Go to the Configuration tab of your AWS Lambda
  2. Under General configuration, click edit
  3. Change the timeout to 0min 30sec.
  4. Click "Save"

IAM Role Configuration

Screenshot 2023-09-21 at 1.01.22 PM.png

When you create an AWS Lambda, by default an IAM role is generated for you. This role does not have permissions to retrieve secrets stored in AWS Parameter Store (explained later). Follow these steps to add permissions using a AWS managed role, or create your own policy from strach to suit your needs.

  1. Go to the Configuration tab of your AWS Lambda
  2. Click on the Permissions section
  3. The section will provide a link to IAM for the role that the Lambda is using. It is listed as the `Role name` of the function. Click this link to go to IAM.
  4. Click on Add Permission -> Attach Policy
  5. Search for `AmazonSSMReadOnlyAccess`, which is an AWS managed role that provides read only access to AWS Systems Manager.
  6. Check the box next to the role to select it and click "Add Permissions".

Write and Upload Lambda Function

This tutorial will use a github repository that I have created for using the Viam Python SDK within an AWS Lambda. Either clone the repository by following the below or download the files directly from this repository on github: https://github.com/michaellee1019/viam-aws-lambda


git clone git@github.com:michaellee1019/viam-aws-lambda.git


You can edit the lambda function as you see fit. The code is within the lambda_functions.py file. It currently behaves as follows:

  • Octoprint will send a percent progress field as part of the webhook event. It uses this event to display "PRINTXXX" and will range from "PRINT 1" to "PRINT100" as the print progresses.
  • I have a Prusa MK3S+ with an MMU integrated. Octoprint will send events when the printer requires attention, usually when filament runs out or a change failed. In this case this display will show "HELP NOW".
  • If there is an event past 10PM, the display turns off. I have this device in my master bedroom + office and rather not see it at night.

If you want to edit this logic, do so now. Then proceed with uploading the code to AWS. Run the following command to generate a zip file and upload to AWS Lambda:


make full-workflow function=PrinterStatus


The script will generate a zip file containing the lambda code and any dependencies that are require to run the lambda, such as the Viam SDK. It uses docker to build the correct version of dependencies that is compatible with AWS Lambda's runtime. The script uses the credentials you have setup in the AWS CLI to upload the zip file to the Lambda function specified in the function argument.

Test the Lambda Function

Screenshot 2023-09-21 at 9.38.29 AM.png

Next, test your lambda function to make sure this part of the integration works:

1. Navigate to the "Test" tab of your AWS Lambda

2. Configure a new test event called "96percent" with the following payload:

{
  "progress": {
    "completion": 96.01335904360904,
    "filepos": 1963815,
    "printTime": 6051,
    "printTimeLeft": 380,
    "printTimeLeftOrigin": "linear"
  },
  "currentZ": 1.6,
  "currentTime": 1695263409,
  "robots": [
    "printerstatus"
  ]
}

3. Click the "Test" button. The lambda should execute and return green status, resulting in the LED displays showing "PRINT 96".

AWS API Gateway

Screenshot 2023-09-21 at 11.45.59 AM.png
Screenshot 2023-09-21 at 11.48.46 AM.png
Screenshot 2023-09-21 at 11.49.40 AM.png
Screenshot 2023-09-21 at 12.30.43 PM.png
Screenshot 2023-09-21 at 12.08.52 PM.png
Screenshot 2023-09-21 at 11.55.33 AM.png
Screenshot 2023-09-21 at 12.00.06 PM.png
Screenshot 2023-09-21 at 12.02.56 PM.png
Screenshot 2023-09-21 at 12.39.15 PM.png
Screenshot 2023-09-21 at 12.39.44 PM.png

Next we will implement a public domain name that can be used to invoke the AWS Lambda. This will be used by OctoPrint to send HTTP POST events with the webhook payload.

  1. Navigate to API Gateway in your preferred AWS Region. For example https://us-east-1.console.aws.amazon.com/apigateway/main/apis?region=us-east-1
  2. Click "Create API"
  3. Under the REST API section click "Build"
  4. Choose "New API" and enter the name of "PrinterStatus".
  5. Click "Create API"
  6. You should be presented with a UI on the default "/" path of the API. Click "Create Method" on this page
  7. Choose "Post" in the method dropdown. Then choose the Lambda function you created earlier from the dropdown.
  8. Click "Create Method"
  9. Under "Method request settings" click "Edit".
  10. Check the box "API Key Required" and click "Save".
  11. Back on the API settings page. Click "Deploy API"
  12. Select "*new stage*" and type in "live" as the stage name.
  13. Click "Deploy" to publish the API.
  14. Click on "Usage Plans" on the left menu
  15. Click "Create Usage Plan"
  16. Fill out the form as follows and Click "Create Usage Plan"
  17. Name: PrinterStatus
  18. Throttling: Enabled
  19. Rate: 1
  20. Burst: 1
  21. Quota: Disabled
  22. Click "API Keys" on the left menu
  23. Click "Create API Key"
  24. Name the key "PrinterStatus" and click "Create API Key"
  25. Select the API on the API keys list page and Choose "Actions" -> "Add to usage plan".
  26. Select the "PrinterStatus" usage plan and click "Save"
  27. Return back to the "Usage Plans" page and select the "PrinterStatus" plan.
  28. Under "Associated stages" click "Add Stage"
  29. Select "PrinterStatus" API and "live" stage and click "Add to usage plan".
  30. Return back to the API settings page and deploy the API once more to the "live" stage. This will enable authentication and rate limiting on the API.


Test the API

Screenshot 2023-09-21 at 12.47.21 PM.png
Screenshot 2023-09-21 at 12.46.53 PM.png

I recommend testing the API using Postman, which is a useful tool for troubleshooting APIs. You can grab the Invoke URL from the API settings page, under the stages option on the left menu. along with the API Key from the API Key settings page.You can use the same payload as the previous step, when testing the Lambda function, in the body of the Postman request.

If all settings are correct up to this point, you should receive a 200 response in Postman, and the LED displays the new progress percentage.

OctoPrint Configuration

Screenshot 2023-09-21 at 1.07.45 PM.png
Screenshot 2023-09-21 at 1.15.59 PM.png

The last step is to setup configuration of the Webhooks plugin within OctoPrint settings.

1. Open Octoprint settings and click on Webhooks on the left.

2. Click "New Hook".

3. Populate the following settings:

  1. Enabled: Checked
  2. URL: Paste in the Invoke URL you used in your postman settings

4. Under events, Check the following:

  1. PRINT STARTED
  2. PRINT DONE
  3. PRINT PROGRESS
  4. Set the interval to 1, so you will receive events everytime the print progress has increased by 1%.

5. Under Advanced, paste the following JSON into Headers and populate your API Gateway API Key:

{
 "Content-Type": "application/json",
 "X-API-KEY": <API Gateway API Key>
}

6. Under Advanced, paste the following JSON into Body:

{
 "progress": "@progress",
 "currentZ": "@currentZ",
 "currentTime": "@currentTime",
 "robots": ["printerstatus"]
}


Start printing and see the magic work!