Merge branch 'dev' into master
This commit was merged in pull request #154.
This commit is contained in:
@@ -200,8 +200,5 @@ You just need to add the following section:
|
||||
- control
|
||||
- gcodeviewer
|
||||
- terminal
|
||||
- plugin_enclosure<code><pre>
|
||||
|
||||
|
||||
|
||||
|
||||
- plugin_enclosure
|
||||
</code></pre>
|
||||
@@ -122,11 +122,22 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin,
|
||||
self.print_complete = False
|
||||
|
||||
def get_settings_version(self):
|
||||
return 5
|
||||
return 6
|
||||
|
||||
def on_settings_migrate(self, target, current):
|
||||
def on_settings_migrate(self, target, current=None):
|
||||
self._logger.warn(
|
||||
"######### current settings version %s target settings version %s #########", current, target)
|
||||
|
||||
if current >= 4 and target == 6:
|
||||
self._logger.warn(
|
||||
"######### migrating settings to v6 #########")
|
||||
old_outputs = self._settings.get(["rpi_outputs"])
|
||||
for rpi_output in old_outputs:
|
||||
if 'shutdown_on_failed' not in rpi_output:
|
||||
rpi_output['shutdown_on_failed'] = False
|
||||
if 'shell_script' not in rpi_output:
|
||||
rpi_output['shell_script'] = ""
|
||||
|
||||
if current == 4 and target == 5:
|
||||
self._logger.warn(
|
||||
"######### migrating settings from v4 to v5 #########")
|
||||
@@ -172,7 +183,6 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin,
|
||||
val = GPIO.input(pin) if not rpi_output['active_low'] else (
|
||||
not GPIO.input(pin))
|
||||
index = self.to_int(rpi_output['index_id'])
|
||||
# result.append(dict(index_id=rpi_output['index_id'], value=val))
|
||||
gpio_status.append(dict(index_id=index, status=val))
|
||||
return flask.Response(json.dumps(gpio_status), mimetype='application/json')
|
||||
|
||||
@@ -186,6 +196,14 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin,
|
||||
self.write_gpio(self.to_int(rpi_output['gpio_pin']), val)
|
||||
return flask.jsonify(success=True)
|
||||
|
||||
@octoprint.plugin.BlueprintPlugin.route("/sendShellCommand", methods=["GET"])
|
||||
def send_send_shell_command(self):
|
||||
output_index = self.to_int(flask.request.values["index_id"])
|
||||
rpi_output = [r_out for r_out in self.rpi_outputs if self.to_int(
|
||||
r_out['index_id']) == output_index].pop()
|
||||
self.send_gcode_command(rpi_output['shell_script'])
|
||||
return flask.jsonify(success=True)
|
||||
|
||||
@octoprint.plugin.BlueprintPlugin.route("/setAutoStartUp", methods=["GET"])
|
||||
def set_auto_startup(self):
|
||||
index = flask.request.values["index_id"]
|
||||
@@ -273,6 +291,19 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin,
|
||||
|
||||
return flask.jsonify(success=True)
|
||||
|
||||
def send_shell_command(self, command):
|
||||
try:
|
||||
stdout = (Popen(command, shell=True, stdout=PIPE).stdout).read()
|
||||
|
||||
response = stdout or "Command executed with no return value."
|
||||
|
||||
self._plugin_manager.send_plugin_message(
|
||||
self._identifier, dict(is_msg=True, msg=response, msg_type="success"))
|
||||
except Exception as ex:
|
||||
self.log_error(ex)
|
||||
self._plugin_manager.send_plugin_message(
|
||||
self._identifier, dict(is_msg=True, msg="Could not execute shell script", msg_type="error"))
|
||||
|
||||
def send_neopixel_command(self, led_pin, led_count, led_brightness, red, green, blue, address,
|
||||
neopixel_dirrect, index_id, queue_id=None):
|
||||
"""Send neopixel command
|
||||
@@ -839,7 +870,7 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin,
|
||||
tempstr + " as pin numbers. Please update GPIO accordingly!"
|
||||
self._logger.info(warn_msg)
|
||||
self._plugin_manager.send_plugin_message(
|
||||
self._identifier, dict(isMsg=True, msg=warn_msg))
|
||||
self._identifier, dict(is_msg=True, msg=warn_msg, msg_type="error"))
|
||||
GPIO.setwarnings(False)
|
||||
except Exception as ex:
|
||||
self.log_error(ex)
|
||||
@@ -1032,33 +1063,37 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin,
|
||||
if self._settings.get(["debug"]) is True:
|
||||
self._logger.info(
|
||||
"GPIO event triggered on channel %s", channel)
|
||||
for rpi_input in [r_inp for r_inp in self.rpi_inputs if self.to_int(r_inp['gpio_pin']) == self.to_int(channel)]:
|
||||
gpio_pin = self.to_int(rpi_input['gpio_pin'])
|
||||
controlled_io = self.to_int(rpi_input['controlled_io'])
|
||||
if (rpi_input['edge'] == 'fall') ^ GPIO.input(gpio_pin):
|
||||
rpi_output = [r_out for r_out in self.rpi_outputs if self.to_int(
|
||||
r_out['index_id']) == controlled_io].pop()
|
||||
if rpi_output['output_type'] == 'regular':
|
||||
if rpi_input['controlled_io_set_value'] == 'toggle':
|
||||
val = GPIO.LOW if GPIO.input(self.to_int(
|
||||
rpi_output['gpio_pin'])) == GPIO.HIGH else GPIO.HIGH
|
||||
else:
|
||||
val = GPIO.LOW if rpi_input['controlled_io_set_value'] == 'low' else GPIO.HIGH
|
||||
self.write_gpio(self.to_int(
|
||||
rpi_output['gpio_pin']), val)
|
||||
for notification in self.notifications:
|
||||
if notification['gpioAction']:
|
||||
msg = "GPIO control action caused by input " + str(rpi_input['label']) + ". Setting GPIO" + str(
|
||||
rpi_input['controlled_io']) + " to: " + str(rpi_input['controlled_io_set_value'])
|
||||
self.send_notification(msg)
|
||||
if rpi_output['output_type'] == 'gcode_output':
|
||||
self.send_gcode_command(rpi_output['gcode'])
|
||||
for notification in self.notifications:
|
||||
if notification['gpioAction']:
|
||||
msg = "GPIO control action caused by input " + \
|
||||
str(rpi_input['label']) + \
|
||||
". Sending GCODE command"
|
||||
self.send_notification(msg)
|
||||
rpi_input = [r_inp for r_inp in self.rpi_inputs if self.to_int(
|
||||
r_inp['gpio_pin']) == self.to_int(channel)].pop()
|
||||
gpio_pin = self.to_int(rpi_input['gpio_pin'])
|
||||
controlled_io = self.to_int(rpi_input['controlled_io'])
|
||||
if (rpi_input['edge'] == 'fall') ^ GPIO.input(gpio_pin):
|
||||
rpi_output = [r_out for r_out in self.rpi_outputs if self.to_int(
|
||||
r_out['index_id']) == controlled_io].pop()
|
||||
if rpi_output['output_type'] == 'regular':
|
||||
if rpi_input['controlled_io_set_value'] == 'toggle':
|
||||
val = GPIO.LOW if GPIO.input(self.to_int(
|
||||
rpi_output['gpio_pin'])) == GPIO.HIGH else GPIO.HIGH
|
||||
else:
|
||||
val = GPIO.LOW if rpi_input['controlled_io_set_value'] == 'low' else GPIO.HIGH
|
||||
self.write_gpio(self.to_int(
|
||||
rpi_output['gpio_pin']), val)
|
||||
for notification in self.notifications:
|
||||
if notification['gpioAction']:
|
||||
msg = "GPIO control action caused by input " + str(rpi_input['label']) + ". Setting GPIO" + str(
|
||||
rpi_input['controlled_io']) + " to: " + str(rpi_input['controlled_io_set_value'])
|
||||
self.send_notification(msg)
|
||||
if rpi_output['output_type'] == 'gcode_output':
|
||||
self.send_gcode_command(rpi_output['gcode'])
|
||||
for notification in self.notifications:
|
||||
if notification['gpioAction']:
|
||||
msg = "GPIO control action caused by input " + \
|
||||
str(rpi_input['label']) + \
|
||||
". Sending GCODE command"
|
||||
self.send_notification(msg)
|
||||
if rpi_output['output_type'] == 'shell_output':
|
||||
command = rpi_output['shell_script']
|
||||
self.shell_command(command)
|
||||
except Exception as ex:
|
||||
self.log_error(ex)
|
||||
pass
|
||||
@@ -1088,11 +1123,20 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin,
|
||||
self._printer.cancel_print()
|
||||
elif rpi_input['printer_action'] == 'toggle':
|
||||
self._logger.info("Printer action toggle.")
|
||||
if self._printer.is_operational():
|
||||
self._printer.toggle_pause_print()
|
||||
else:
|
||||
self._printer.connect()
|
||||
elif rpi_input['printer_action'] == 'start':
|
||||
self._logger.info("Printer action start.")
|
||||
self._printer.start_print()
|
||||
elif rpi_input['printer_action'] == 'toggle_job':
|
||||
self._logger.info("Printer action toggle_job.")
|
||||
if self._printer.is_operational():
|
||||
if self._printer.is_printing():
|
||||
self._printer.pause_print()
|
||||
elif self._printer.is_paused():
|
||||
self._printer.resume_print()
|
||||
self._printer.cancel_print()
|
||||
elif self._printer.is_ready():
|
||||
self._printer.start_print()
|
||||
else:
|
||||
self._printer.connect()
|
||||
elif rpi_input['printer_action'] == 'stop_temp_hum_control':
|
||||
@@ -1238,8 +1282,6 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin,
|
||||
delay_seconds = self.to_float(shutdown_time)
|
||||
self.schedule_auto_shutdown_outputs(
|
||||
rpi_output, delay_seconds)
|
||||
if rpi_output['output_type'] == 'temp_hum_control':
|
||||
rpi_output['temp_ctr_set_value'] = 0
|
||||
self.run_tasks()
|
||||
self.update_ui()
|
||||
|
||||
@@ -1292,6 +1334,10 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin,
|
||||
if (rpi_output['output_type'] == 'neopixel_indirect' or rpi_output['output_type'] == 'neopixel_direct'):
|
||||
self.add_neopixel_output_to_queue(
|
||||
rpi_output, shutdown_delay_seconds, 0, 0, 0, sufix)
|
||||
if rpi_output['output_type'] == 'temp_hum_control':
|
||||
value = 0
|
||||
self.add_temperature_output_temperature_queue(
|
||||
delay_seconds, rpi_output, value, sufix)
|
||||
if self._settings.get(["debug"]) is True:
|
||||
self._logger.info("Events scheduled to run %s", self.event_queue)
|
||||
|
||||
@@ -1334,7 +1380,9 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin,
|
||||
self.add_neopixel_output_to_queue(
|
||||
rpi_output, delay_seconds, red, green, blue, sufix)
|
||||
if rpi_output['output_type'] == 'temp_hum_control':
|
||||
rpi_output['temp_ctr_set_value'] = rpi_output['temp_ctr_default_value']
|
||||
value = rpi_output['temp_ctr_default_value']
|
||||
self.add_temperature_output_temperature_queue(
|
||||
delay_seconds, rpi_output, value, sufix)
|
||||
if self._settings.get(["debug"]) is True:
|
||||
self._logger.info("Events scheduled to run %s", self.event_queue)
|
||||
|
||||
@@ -1423,6 +1471,43 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin,
|
||||
|
||||
self.event_queue.append(dict(queue_id=queue_id, thread=thread))
|
||||
|
||||
def add_temperature_output_temperature_queue(self, delay_seconds, rpi_output, value, sufix):
|
||||
queue_id = '{0!s}_{1!s}'.format(rpi_output['index_id'], sufix)
|
||||
if self._settings.get(["debug"]) is True:
|
||||
self._logger.info(
|
||||
"Scheduling temperature control id %s on %s delay_seconds", queue_id, delay_seconds)
|
||||
|
||||
thread = threading.Timer(delay_seconds,
|
||||
self.write_temperature_to_output,
|
||||
args=[self.to_int(rpi_output['index_id']), value, queue_id])
|
||||
|
||||
self.event_queue.append(dict(queue_id=queue_id, thread=thread))
|
||||
|
||||
def write_temperature_to_output(self, rpi_output_index, value, queue_id=None):
|
||||
try:
|
||||
rpi_output = [r_out for r_out in self.rpi_outputs if self.to_int(
|
||||
r_out['index_id']) == rpi_output_index].pop()
|
||||
|
||||
if rpi_output['output_type'] == 'temp_hum_control':
|
||||
rpi_output['temp_ctr_set_value'] = value
|
||||
|
||||
if self._settings.get(["debug"]) is True:
|
||||
if queue_id is not None:
|
||||
self._logger.info("Runing scheduled queue id %s", queue_id)
|
||||
self._logger.info(
|
||||
"Setting temperature to output index: %s value %s", rpi_output['index_id'], value)
|
||||
|
||||
self.update_ui()
|
||||
if queue_id is not None:
|
||||
self.stop_queue_item(queue_id)
|
||||
|
||||
except Exception as ex:
|
||||
template = "An exception of type {0} occurred on {1} when writing on pin {2}. Arguments:\n{3!r}"
|
||||
message = template.format(
|
||||
type(ex).__name__, inspect.currentframe().f_code.co_name, gpio, ex.args)
|
||||
self._logger.warn(message)
|
||||
pass
|
||||
|
||||
def get_startup_delay_from_output(self, rpi_output):
|
||||
start_up_time = rpi_output['startup_time']
|
||||
if self.is_hour(start_up_time):
|
||||
|
||||
@@ -21,7 +21,7 @@ $(function () {
|
||||
|
||||
self.settings_possible_outputs = ko.pureComputed(function () {
|
||||
return ko.utils.arrayFilter(self.settingsViewModel.settings.plugins.enclosure.rpi_outputs(), function (item) {
|
||||
return ((item.output_type() === "regular" && !item.toggle_timer()) || item.output_type() === "gcode_output");
|
||||
return ((item.output_type() === "regular" && !item.toggle_timer()) || item.output_type() === "gcode_output" || item.output_type() === "shell_output");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -236,11 +236,11 @@ $(function () {
|
||||
})
|
||||
}
|
||||
|
||||
if (data.isMsg) {
|
||||
if (data.is_msg) {
|
||||
new PNotify({
|
||||
title: "Enclosure",
|
||||
text: data.msg,
|
||||
type: "error"
|
||||
type: data.msg_type
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -362,6 +362,7 @@ $(function () {
|
||||
index_id: ko.observable(nextIndex),
|
||||
label: ko.observable("Ouput " + nextIndex),
|
||||
output_type: ko.observable("regular"),
|
||||
shell_script: ko.observable(""),
|
||||
gpio_pin: ko.observable(0),
|
||||
gpio_status: ko.observable(false),
|
||||
hide_btn_ui: ko.observable(false),
|
||||
@@ -510,6 +511,19 @@ $(function () {
|
||||
});
|
||||
};
|
||||
|
||||
self.handleShellOutput = function (item, form) {
|
||||
var request = {
|
||||
"index_id": item.index_id()
|
||||
};
|
||||
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
dataType: "json",
|
||||
data: request,
|
||||
url: self.buildPluginUrl("/sendShellCommand")
|
||||
});
|
||||
};
|
||||
|
||||
self.switchAutoStartUp = function (item) {
|
||||
|
||||
var request = {
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
</a>
|
||||
<ul class="dropdown-menu" data-bind="foreach: $root.rpi_outputs()">
|
||||
<!-- ko if: ($data.show_on_navbar()) -->
|
||||
|
||||
<!-- ko if: ($data.output_type() == "regular") -->
|
||||
<li>
|
||||
<a href="javascript:void(0)" data-bind="click: $root.handleIO">
|
||||
@@ -38,6 +39,15 @@
|
||||
<!-- /ko -->
|
||||
<!-- /ko -->
|
||||
|
||||
<!-- ko if: ($data.output_type() == "shell_output") -->
|
||||
<li>
|
||||
<a href="javascript:void(0)" data-bind="click: $root.handleShellOutput">
|
||||
<span data-bind="html: label"> </span>
|
||||
<span class="badge badge-info">shell</span>
|
||||
</a>
|
||||
</li>
|
||||
<!-- /ko -->
|
||||
|
||||
<!-- /ko -->
|
||||
|
||||
</ul>
|
||||
|
||||
@@ -53,6 +53,12 @@
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="controls">
|
||||
<label class="radio">
|
||||
<input type="radio" value="shell_output" data-bind="checked: output_type, attr: {name: 'output_type_' + $index() }"> {{ _('Shell Script') }}
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<!-- ko if: ($data.output_type() != "temperature_alarm") -->
|
||||
<div class="control-group">
|
||||
@@ -70,6 +76,15 @@
|
||||
<span class="help-inline">Id used for API control</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- ko if: ($data.output_type() == "shell_output") -->
|
||||
<div class="control-group">
|
||||
<label class="control-label">{{ _('Script') }}</label>
|
||||
<div class="controls">
|
||||
<input type="text" class="input-block-level" data-bind="value: shell_script">
|
||||
<span class="help-inline">Shell script to be executed</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- /ko -->
|
||||
<!-- ko ifnot: ($data.output_type() == "gcode_output" || $data.output_type() == "temperature_alarm" ) -->
|
||||
<div class="control-group">
|
||||
<label class="control-label">{{ _('IO Number') }}</label>
|
||||
@@ -88,45 +103,45 @@
|
||||
</div>
|
||||
<!-- /ko -->
|
||||
|
||||
|
||||
<!-- ko if: ($data.output_type() == "pwm" ) -->
|
||||
<div class="control-group">
|
||||
<div class="controls">
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" data-bind="checked: pwm_temperature_linked"> {{ _('Link PWM to Temperature') }}
|
||||
</label>
|
||||
<span class="help-inline">Link PWM ouput to temperature. PWM output will be interpolated between the point from duty A, temperature A -> duty B, temperature B.
|
||||
This output will automatomatically start when a print starts and will default to the default duty cycle when print is complete.
|
||||
</span>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<div class="controls">
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" data-bind="checked: pwm_temperature_linked"> {{ _('Link PWM to Temperature') }}
|
||||
</label>
|
||||
<span class="help-inline">Link PWM ouput to temperature. PWM output will be interpolated between the point from duty A, temperature A -> duty
|
||||
B, temperature B. This output will automatomatically start when a print starts and will default to the default
|
||||
duty cycle when print is complete.
|
||||
</span>
|
||||
</div>
|
||||
<!-- /ko -->
|
||||
</div>
|
||||
<!-- /ko -->
|
||||
|
||||
<!-- ko if: ($data.output_type() == "pwm" && $data.pwm_temperature_linked()) -->
|
||||
<div class="control-group">
|
||||
<label class="control-label">{{ _('Duty A') }}</label>
|
||||
<div class="controls">
|
||||
<input type="text" class="input-block-level" data-bind="value: duty_a">
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label">{{ _('Duty A') }}</label>
|
||||
<div class="controls">
|
||||
<input type="text" class="input-block-level" data-bind="value: duty_a">
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label">{{ _('Temperature A') }}</label>
|
||||
<div class="controls">
|
||||
<input type="text" class="input-block-level" data-bind="value: temperature_a">
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label">{{ _('Temperature A') }}</label>
|
||||
<div class="controls">
|
||||
<input type="text" class="input-block-level" data-bind="value: temperature_a">
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label">{{ _('Duty B') }}</label>
|
||||
<div class="controls">
|
||||
<input type="text" class="input-block-level" data-bind="value: duty_b">
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label">{{ _('Duty B') }}</label>
|
||||
<div class="controls">
|
||||
<input type="text" class="input-block-level" data-bind="value: duty_b">
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label">{{ _('Temperature B') }}</label>
|
||||
<div class="controls">
|
||||
<input type="text" class="input-block-level" data-bind="value: temperature_b">
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label">{{ _('Temperature B') }}</label>
|
||||
<div class="controls">
|
||||
<input type="text" class="input-block-level" data-bind="value: temperature_b">
|
||||
</div>
|
||||
</div>
|
||||
<!-- /ko -->
|
||||
|
||||
<!-- ko if: ($data.output_type() == "regular" || ($data.output_type() == "pwm" && !$data.pwm_temperature_linked()) ) -->
|
||||
@@ -221,15 +236,16 @@
|
||||
<span class="help-inline">Time delay in secconds to turn on GPIO when print starts OR exact time that the event should happen, note that
|
||||
events will only be scheduled after a print starts, time should be formated as HH:MM on a 24 hours format, don't
|
||||
forget to check timezone of your raspberry pi.</span>
|
||||
<span class="label label-important">Attention</span>
|
||||
<span> Hour schedule does not work with <b>Link PWM to Temperature</b> option</span>
|
||||
<span class="label label-important">Attention</span>
|
||||
<span> Hour schedule does not work with
|
||||
<b>Link PWM to Temperature</b> option</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- /ko -->
|
||||
<!-- /ko -->
|
||||
|
||||
<!-- ko if: ($data.output_type() == "regular" || $data.output_type() == "temp_hum_control") -->
|
||||
<!-- ko if: ($data.output_type() == "regular" || $data.output_type() == "temp_hum_control" ) -->
|
||||
<div class="control-group">
|
||||
<div class="controls">
|
||||
<label class="checkbox">
|
||||
@@ -240,7 +256,7 @@
|
||||
</div>
|
||||
<!-- /ko -->
|
||||
|
||||
<!-- ko if: ($data.output_type() == "regular" || $data.output_type() == "gcode_output" ) -->
|
||||
<!-- ko if: ($data.output_type() == "regular" || $data.output_type() == "gcode_output" || $data.output_type() == "shell_output") -->
|
||||
<div class="control-group">
|
||||
<div class="controls">
|
||||
<label class="checkbox">
|
||||
@@ -649,7 +665,9 @@
|
||||
<option value="resume">Printer Resume</option>
|
||||
<option value="pause">Printer Pause</option>
|
||||
<option value="cancel">Printer Cancel</option>
|
||||
<option value="start">Start Print</option>
|
||||
<option value="toggle">Printer Toggle (Connect / Pause / Resume)</option>
|
||||
<option value="toggle_job">Job Toggle (Connect / Start / Cancel)</option>
|
||||
<option value="stop_temp_hum_control">Stop Temperature Control</option>
|
||||
</select>
|
||||
<span class="help-inline"> You can use filament change on your filament detectors and add buttons to resume and pause the print job.</span>
|
||||
|
||||
@@ -170,6 +170,16 @@
|
||||
</div>
|
||||
<!-- /ko -->
|
||||
|
||||
<!-- ko if: ($data.output_type() == "shell_output") -->
|
||||
<h4>
|
||||
<span data-bind="html: label"> </span>
|
||||
<span class="badge">Shell Script</span>
|
||||
</h4>
|
||||
<div>
|
||||
<button data-bind="enable: $root.isUser(), click: $root.handleShellOutput" class="btn">Execute Script</button>
|
||||
</div>
|
||||
<!-- /ko -->
|
||||
|
||||
<!-- ko if: ($data.output_type() == "pwm") -->
|
||||
<h4>
|
||||
<span data-bind="html: label"> </span>
|
||||
@@ -292,4 +302,4 @@
|
||||
<!-- /ko -->
|
||||
</h4>
|
||||
<!-- /ko -->
|
||||
<!-- /ko -->
|
||||
<!-- /ko -->
|
||||
Reference in New Issue
Block a user