Sending data from plugin to navbar doesn´t work

What is the problem?

I try to write a plugin for my Octoprint installation and I want to send some sensor data to a field in the navbar, but the values don´t get updated. The value stays constant to 4.32.

What did you already try to solve it?

No, because I don´t figure out the problem.

Additional information about your setup

SpoolScale_navbar.jinja2

<div class="navbar-text">
    <span id="weight" data-bind="html: settings.settings.plugins.SpoolScale.Weight"></span> g
</div>

init.py

class SpoolscalePlugin(octoprint.plugin.StartupPlugin,
                        octoprint.plugin.AssetPlugin,
                        octoprint.plugin.TemplatePlugin,
                        octoprint.plugin.SettingsPlugin):

	def __init__(self):
		self.__Settings = dict()
		self.__Settings["DOUT"] = 17
		self.__Settings["SCK"] = 4
		self.__Settings["Weight"] = 4.32
		self.__HX = HX711.HX711(DOUT = int(self.__Settings["DOUT"]), SCK = int(self.__Settings["SCK"]))

	def __StartTimer(self):
		self.__UpdateTimer = RepeatedTimer(1, self.on_Timer, run_first = True)
		self.__UpdateTimer.start()

	def on_Timer(self):
		self._logger.info(self._identifier)
		self._plugin_manager.send_plugin_message(self._identifier,
												dict(Weight = int(random() * 100))
												)

	def on_after_startup(self):
		self._logger.info("Version: {}")
		self.__StartTimer()

	def on_shutdown(self):
		if(self.__HX):
			del self.__HX

	def on_settings_save(self, data):
		self.__HX = HX711.HX711(DOUT = int(self.__Settings["DOUT"]), SCK = int(self.__Settings["SCK"]))

	def get_template_configs(self):
		return [
			dict(type = "navbar", custom_bindings = False),
			dict(type = "settings", custom_bindings = False)
		]

	def get_settings_defaults(self):
		return self.__Settings

	def get_assets(self):
		return {
			"js": ["js/SpoolScale.js"],
			"css": ["css/SpoolScale.css"],
			"less": ["less/SpoolScale.less"]
		}

	def get_update_information(self):
		return {
			"SpoolScale": {
				"displayName": "Spoolscale Plugin",
				"displayVersion": self._plugin_version,

				# version check: github repository
				"type": "github_release",
				"user": "kampi",
				"repo": "OctoPrint-Spoolscale",
				"current": self._plugin_version,

				# update method: pip
				"pip": "https://github.com/kampi/OctoPrint-Spoolscale/archive/{target_version}.zip",
			}
		}

__plugin_name__ = "Spool Scale"
__plugin_pythoncompat__ = ">3,<4"

def __plugin_load__():
	global __plugin_implementation__
	__plugin_implementation__ = SpoolscalePlugin()

	global __plugin_hooks__
	__plugin_hooks__ = {
		"octoprint.plugin.softwareupdate.check_config": __plugin_implementation__.get_update_information
	}

Do you have a JavaScript file as well?

In your Jinja template there, you're binding to the settings value. It looks like you are trying to update a value using the websocket though, so binding to the settings will not work. You need some JavaScript to receive the websocket message & handle updating the values in the frontend.

Hi,

I don´t have a Javascript file. Can you please provide me an example snippet so I can take a look at it?

you need the js file, the easiest way is to use the cookiecutter instructions on the docs site for developing plugins as it will create all the files for you. but end goal, you need to have something like this in the js file viewModel...

self.onDataUpdaterPluginMessage = function(plugin, data) {
  if(plugin !== "<put pluginidentifier here>") {
    return
  }

  // update observable here.
  self.my_bound_observable(data["Weight"]);

Here's a very elaborate example...

BTW...this plugin already exists for you....

Yes, I know this plugin, but I want to modify it and I want to learn the procedure for new plugins :slight_smile:

Less elaborate example from the NavbarTemp plugin:

Edit:

Found the mistake. self.Weight must be changed to Weight. But why do I have to change it? The code snippet from NavbarTemperature use self.xy too.


I have updated my code, based on the code snippet:

SpoolScale_navbar.jinja2

<div class="navbar-text">
    <span id="weight" data-bind="html: Weight()"></span> g
</div>

SpoolScale.js

$(function()
{
    function SpoolscaleViewModel(parameters)
	{
        var self = this;
		self.Weight = ko.observable("");

        self.onDataUpdaterPluginMessage = function(plugin, data)
		{
            if((plugin != "SpoolScale") || (!data))
			{
                return;
            }

			if(data.Weight)
			{
				self.Weight(data.Weight);
			}
        };
    }

    OCTOPRINT_VIEWMODELS.push({
        construct: SpoolscaleViewModel,
        // ViewModels your plugin depends on, e.g. loginStateViewModel, settingsViewModel, ...
        dependencies: [ /* "loginStateViewModel", "settingsViewModel" */ ],
        // Elements to bind to, e.g. #settings_plugin_SpoolScale, #tab_plugin_SpoolScale, ...
        elements: [ /* ... */ ]
    });
});

But my browser (Chrome) output this error:

Could not bind view model NavigationViewModel to target #navbar : ReferenceError: Unable to process binding "html: function(){return Weight() }"
Message: Weight is not defined

What part is missing here? It looks like an error in my jinja2 template, but how can I fix it?

This needs to have the selector for your navbar items so knockout knows what it's binding to.