Merge branch 'dev' into master

This commit was merged in pull request #154.
This commit is contained in:
Vitor de Miranda Henrique
2018-06-18 15:17:15 -05:00
committed by GitHub
6 changed files with 215 additions and 81 deletions

View File

@@ -200,8 +200,5 @@ You just need to add the following section:
- control
- gcodeviewer
- terminal
- plugin_enclosure<code><pre>
- plugin_enclosure
</code></pre>

View File

@@ -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):

View File

@@ -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 = {

View File

@@ -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>

View File

@@ -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>

View File

@@ -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 -->