This post is a series of posts in which I detail my journey to bring OctoPrint to the Seeed Studio reTerminal.
Day 4
In today’s post we’ll be with learning how to make an OctoPrint Plugin including how to make it distributable.
Contents
Day 1 – 05–09–22 – Getting Started:
- Getting Started – 05/09/2022
- My Initial Plans
- Cloning the Repos
- A pointer in the right direction from the folks at OctoPrint3D – Plugins
- OctoPrint Plugin Mixin Development Docs
- Getting the Development Environment setup
- Installing Python
- Checking out the OctoPrint Sources
- Creating and Activating a Virtual Environment
- Build Tools for Visual Studio 2019
- Setting up VirtualEnv
- Adding VirtualEnv to the Windows Path
- Upgrading Pip
- Setting up the Virtual Environment
Day 2 – 06–09–22 – Setting up the Environment:
- OctoEverywhere – 06-09-22
- Continuing with VirtualEnv
- Activating the Virtual Environment
- Setting up the Virtual Environment
- Installing Microsoft Visual C++ 14.0
- Using pip to install packages in the Virtual Environment
- Git Pre-Commit
- Git Changes, Blame and Ignore
- Configuring VS Code
- Running OctoPrint for the first time
- Changing the Python Interpreter
- Running the OctoPrint from VS Code
Day 3 – 07–09–22 – Setup Wizard:
- Setting up OctoPrint in the Debug Environment – 07-09-22
- Setup Wizard – Access Control
- Setup Wizard – Online Connectivity
- Setup Wizard – Usage Tracking
- Setup Wizard – Plugin Blacklist
- Setup Wizard – Printer Profile
- Setup Wizard – Please Reload
- Setup Wizard – Setup Printer (Again)
- Setup Wizard – Server Commands
- Setup Wizard – Webcam and Timelapse Recordings
- Setup Wizard – Finish
- Virtual 3d Printer Plugin
- Beginning Plugin Development
Plugin Development – 08-09-22
I’d left the development environment running last night, and when I returned to VS Code today, there’s a whole heap of yellow debug messages;
The messages are read;
DeprecationWarning: There is no current event loop
loop = asyncio.get_event_loop()
They seem to be coming from the C:\repos\OctoPrint\venv\lib\site-packages\tornado\ioloop.py
file on line 265.
Looking on Google, I don’t see anything obvious relating directly to OctoPrint itself.
This StackOverflow answer by Stephan202 offers the possibility to just ignore deprecation warnings by adding -W ignore::DeprecationWarning
as a Python parameter. I guess I could do this as part of the launch.json perhaps?
I’ll leave this alone for now though as I’m keen to get going creating my first plugin!
Returning to the official documentation, the first thing it instructs us to do is make sure that our local development environment is setup, which we did over the last couple of days.
It’s apparently possible to develop plugins directly on the Pi if we like, we simple need to activate the oprint
Virtual Environment. We won’t be doing that of course.
Hello World Plugin
First up we need to create a file name helloworld.py
in the OctoPrint plugins
directory, so let’s go ahead and do that;
So, it looks like the path is actually OctoPrint\src\octoprint\plugins
.
Creating a file named helloworld.py
in that directory, and pasting in the content from the blog;
__plugin_name__ = "Hello World"
__plugin_version__ = "1.0.0"
__plugin_description__ = "A quick \"Hello World\" example plugin for OctoPrint"
__plugin_pythoncompat__ = ">=3.7,<4"
Saving the file and running up OctoPrint, we can have a look at the Console Log;
We can see that our new helloworld
plugin has been loaded successfully. We can also see that it’s picked up the Plugin name and the version of 1.0.0.
Of course, this plugin isn’t actually doing anything at all at the moment, and the docs go on to teach us how we can make our plugin do something.
The next step for us is to replace the contents of our helloworld.py
file with;
import octoprint.plugin
class HelloWorldPlugin(octoprint.plugin.StartupPlugin):
def on_after_startup(self):
self._logger.info("Hello World!")
__plugin_name__ = "Hello World"
__plugin_version__ = "1.0.0"
__plugin_description__ = "A quick \"Hello World\" example plugin for OctoPrint"
__plugin_pythoncompat__ = ">=3.7,<4"
__plugin_implementation__ = HelloWorldPlugin()
Restarting OctoPrint now gives us our “Hello World” message in the console log;
So that’s pretty cool, and really straightforward too.
We can see from what we have in the helloworld.py file now, that we’re using the StartupPlugin
plugin mixin that we saw yesterday.
Reminding ourselves of what that plugin does;
The StartupPlugin Mixin
The docs for the StartupPlugin Mixin start with…
The
StartupPlugin
allows hooking into the startup of OctoPrint. It can be used to start up additional services on or just after the startup of the server.
So this makes sense in that we’ve seen the message in the log file when we started OctoPrint up.
Making a Plugin Distributable
The next thing we need to do is convert our single file plugin into something resembling a more complete package which can be installed via the OctoPrint Plugin Manager.
We can do this by first installing the cookiecutter
package. A quick google takes us to the official Cookiecutter page on pypi.org, where we learn that Cookiecutter is;
A command-line utility that creates projects from cookiecutters (project templates), e.g. creating a Python package project from a Python package project template.
To install Cookiecutter, we need to use pip in our OctoPrint virtual environment;
pip install "cookiecutter>=1.4,<1.7"
Looking at the command, it seems the docs require a version greater than or equal to 1.4 and less than 1.7… I wonder why we need those specific versions?
Either way, we can open a new Terminal Window, reactivate the Virtual Environment and run the command;
cd c:/repos/OctoPrint
.\venv\Scripts\activate
pip install "cookiecutter>=1.4,<1.7"
With Cookiecutter installed successfully, we can run a command to create a new helloworld plugin;
octoprint dev plugin:new helloworld
Running this command actually prompts us for the plugin_package
name;
I’m guessing I can just hit return to accept the default of octoprint_helloworld
;
So, hitting return accepts the defaults… So doing this or entering info where I need to, the process completes;
Looking around in the directories, I find our new plugin folder in the root of the OctoPrint project;
Looking back at the docs, I think perhaps I should’ve run this command in my repos directory rather than in the OctoPrint folder… This makes sense, as otherwise our plugin will become source controlled along with the OctoPrint project…
So, let’s delete the new folder and re-run the command in my repos
folder directly…
I guess I could just move the folder, but I mainly want to do that in case there’s some scripting reason I need to move it (I doubt it, but better safe than sorry eh);
Checking my repos directory, I can see our new plugin alongside the OctoPrint directory;
Looking at the contents of our new Plugin older;
We can see we have a set of folders and files created for us… Reading the docs, it appears we are able to delete some of these files if we like;
extras
translations
octoprint_helloworld/static
octoprint_helloworld/templates
With those folders deleted, we can move on. We need to move our existing helloworld.py plugin file to our new plugin and rename it to __init__.py
(Thst’s underscore underscore init underscore underscore .py).