Html button that executes a python function through javascript


#1

I want to have a button in my plugin that can execute a python function or a script. Right now I only want to see info message.
I read a bit about this and i made the following usind SimpleApiPlugin:

under __init__.py I defined the following function:

def on_api_command(self, command, data):
     if command == 'turnOn':
         self._logger.info("button clicked")

under myplugin.js i defined the following:

self.test=function(data)
{
   $.ajax({
                url: /api/plugin/octoprint_myplugin,
                type: "POST",
                dataType: "json"
                data: JSON.stringify(data), command: "turnOn"});
   contentType: "application/json"
}

under myplugin_tab.jinja2 i defined the button that calls the test() function:

<button class="btn" data-bind="click:function(){$data.test();}">Test</button>

As a result I don't see errors but I'm not seeing the info message.
Is it wrong this way or am I missing something?

Thanks for help


#2

I tried fixing the formatting in the snippets you provided, but they still look extremely wrong. Could you just update your code somewhere so that we can take a look the exact code that's not working?


#3

This is my beginner plugin

Many thanks for your kind reply and for your help. I'm totally beginner in octoprint or more specifically in web/server development. I read and found that to have an html button triggering a python function, then there are two options. The first is to use BlueprintPlugins and the second is to use the SimpleApiPlugin. I chose the second option. I read and found that I need to have a function with $ajax in javascript that calls a function on_api_commands() in python by using the octoprint.plugin.SimpleApiPlugin.
I tried but it might be totally wrong. When clicking the button "Test" the server gets refreshed then nothing happens.
Really thankful for your kind support


#4
  • The jinja2 file appears to have a form within a form.
  • I'm seeing inconsistencies on the indentation; python hates that.
  • Lines 10 & 11 in your JavaScript look wrong to me. Try adding hard returns after some of those commas on line 10. It will make it easier to see that the french brace after ip() is possibly in the wrong place.

I didn't see the new tab show up in my interface, having added your plugin.


#5

Many thanks for the notes. I changed it. https://github.com/julian988/trial-plugin . I'm still having the same results. when clicking Test button the server refreshes and then nothing happens.
I don't understand why the myplugin tab doesn't show up by you. (I usually have this case when there's something wrong with the plugin) Have you built (python setup.py dev) the plugin after adding it? I removed the plugin and re-added, reinstalled it and the tab shows up by me. Could you try again.


#6
  1. As @OutsourcedGuru already pointed out, you have mixed spaces and tabs all over your __init__.py. That will probably be the reason why OctoPrint doesn't even detect that you have assets or templates, because the methods your overwrote to provide those aren't properly executed. You need to fix your whitespace. Set your text editor to display whitespace characters and make sure you only user tabs or spaces and everything is uniformly indented. The same holds true for your JS file btw, it's just more forgiving as JS control blocks aren't based on whitespace but brackets.
  2. This definitely doesn't produce the request you want it to produce and in fact isn't even parseable I think. Make your life easier and just use the JS Client Library to perform a request, since with that what you are trying to do just boils down to OctoPrint.simpleApiCommand("myplugin", "turnOn", {"ip": data.ip()}).
  3. Similarly, you are missing quotes around your string here, and the whole declaration of the view model never closes, making the whole plugin JS to fail to even parse
  4. Your tab isn't found because the default subfolder for templates isn't called template but templates.
  5. data.ip() is never declared, so creating the request fails as well since data is undefined and also doesn't have any ip methods. Just putting a simple test string in there for a first handshake is probably a good idea.
  6. Overall, your whole data binding doesn't make much sense the way it is. You've declared a test method on the view model, just use that directly in the click binding, no need for anonymous functions: data-bind="click: test"
  7. on_api_commands gets never called because it's supposed to say on_api_command.

This works:

__init__.py:

# coding=utf-8
from __future__ import absolute_import

__author__ = ""
__license__ = ""
__copyright__ = ""

import octoprint.plugin
import time
import os
import sys
from octoprint.events import eventManager, Events
from octoprint.server.util.flask import restricted_access
from octoprint.server import admin_permission
import json
import flask
import logging

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

    def __init__(self):
       self.commandss=0

    def on_after_startup(self):
        self._logger.info("Starting myplugin Plugin")

    def get_api_commands(self):
        self._logger.info("Manually triggered get_api")
        return dict(turnOn=["ip"])

    def on_api_command(self, command, data):
        if command == 'turnOn':
            self._logger.info("Manually triggered!")

    def get_assets(self):
        return dict(
            js= ["js/myplugin.js"],
            css= ["css/myplugin.css"]
        )

    def get_update_information(self):
        return dict(
            myplugin=dict(
                displayName="myplugin",
                displayVersion=self._plugin_version,

                # version check: github repository
                type="github_release",
                user="",
                repo="octoPrint-myplugin",
                current=self._plugin_version,

                # update method: pip w/ dependency links
                pip=""
            )
        )

__plugin_name__ = "myplugin"

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

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

static/js/myplugin.js:

$(function() {
    function mypluginViewModel(parameters) {
        var self = this;

        self.test = function(data) {
            OctoPrint.simpleApiCommand("myplugin", "turnOn", {"ip": "someIp"});
        };
    }

    ADDITIONAL_VIEWMODELS.push([
        mypluginViewModel,
        ["settingsViewModel"],
        ["#tab_plugin_myplugin"]
    ]);
});

templates/myplugin_tab.jinja2:

<form class="form-horizontal">
   <h3>folder</h3>

    <div class="panel-body">
        <button class="btn" data-bind="click: test">Test</button>
    </div>
</form>

Suggestions:

  • Whitespace is important in any language. In most it makes your code more readable, in Python it's part of the control flow so be very very diligent. Set your text editor to display whitespace characters, make sure they look uniform:
    image
    and not all over the place:
  • Folder and method names are crucial - your stuff won't work if you don't take care to name methods you expect OctoPrint to call and files you expect OctoPrint to find the way it can find them. The documentation is your friend here.
  • Go through the plugin tutorial (again).

#7

Thank you very very much for the nice and detailed explanation.


#8

when i want to change the octoprin webcam zoom , i login with ssh and change de zoom with this comand
v4l2-ctl -c zoom_absolute=1 , can be 1 to 5
i have includen in the
/root/bin/webcamd
my default configuration

# runs MJPG Streamer, using the provided input plugin + configuration

function runMjpgStreamer {
input=$1
pushd $MJPGSTREAMER_HOME &gt; /dev/null 2&gt;&amp;1
echo Running ./mjpg_streamer -o "output_http.so -w $camera_http_webroot $camera_http_options" -i "$input"
LD_LIBRARY_PATH=. ./mjpg_streamer -o "output_http.so -w $camera_http_webroot $camera_http_options" -i "$input" &amp;
v4l2-ctl -c zoom_absolute=2 &amp;
wait
popd &gt; /dev/null 2&gt;&amp;1
} 

is it posible to execute this Linux commands with your HTML code?
thanks a lot