From e8237841dd3966c75541a170400c78a644bd98f9 Mon Sep 17 00:00:00 2001 From: UnchartedBull Date: Tue, 8 Oct 2019 23:28:27 +0200 Subject: [PATCH 01/14] Add Temperature GET API --- octoprint_enclosure/__init__.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/octoprint_enclosure/__init__.py b/octoprint_enclosure/__init__.py index 9c1fc94..103d176 100644 --- a/octoprint_enclosure/__init__.py +++ b/octoprint_enclosure/__init__.py @@ -174,6 +174,18 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP gpio_status.append(dict(index_id=index, status=val)) return flask.Response(json.dumps(gpio_status), mimetype='application/json') + @octoprint.plugin.BlueprintPlugin.route("/getTemperatureStatus", methods=["GET"]) + def get_temperature_status(self): + temperature_status = [] + for rpi_input in self.rpi_input: + if rpi_input['input_type'] == 'temperature_sensor': + temperature = self.to_int(rpi_input['temp_sensor_temp']) + humidity = self.to_int(rpi_input['temp_sensor_humidity']) + index = self.to_int(rpi_input['index_id']) + label = rpi_input['label'] + temperature_status.append(dict(index_id=index, label=label, temperature=temperature, humidity=humidity)) + return flask.Response(json.dumps(temperature_status), mimetype='application/json') + @octoprint.plugin.BlueprintPlugin.route("/setIO", methods=["GET"]) def set_io(self): index = flask.request.values["index_id"] From 0983363b5f7c8a383cb179a0fb9285b0fd85aa2e Mon Sep 17 00:00:00 2001 From: Timon G Date: Wed, 9 Oct 2019 00:38:50 +0200 Subject: [PATCH 02/14] Update setup.py --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 54921de..71166b0 100644 --- a/setup.py +++ b/setup.py @@ -14,7 +14,7 @@ plugin_package = "octoprint_enclosure" plugin_name = "OctoPrint-Enclosure" # The plugin's version. Can be overwritten within OctoPrint's internal data via __plugin_version__ in the plugin module -plugin_version = "4.12" +plugin_version = "4.13" # The plugin's description. Can be overwritten within OctoPrint's internal data via __plugin_description__ in the plugin # module From 5798beeeec51860a45a4aaed6478e646813a0cdc Mon Sep 17 00:00:00 2001 From: UnchartedBull Date: Wed, 9 Oct 2019 13:59:51 +0200 Subject: [PATCH 03/14] first draft for kind of RESTful API --- octoprint_enclosure/__init__.py | 62 +++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 22 deletions(-) diff --git a/octoprint_enclosure/__init__.py b/octoprint_enclosure/__init__.py index 103d176..e786d5d 100644 --- a/octoprint_enclosure/__init__.py +++ b/octoprint_enclosure/__init__.py @@ -142,6 +142,8 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP self.rpi_inputs = self._settings.get(["rpi_inputs"]) # ~~ Blueprintplugin mixin + ## POST /temperature/$id + ## maybe PATCH will be the more official way to do. Feedback? @octoprint.plugin.BlueprintPlugin.route("/setEnclosureTempHum", methods=["GET"]) def set_enclosure_temp_humidity(self): set_value = self.to_float(flask.request.values["set_temperature"]) @@ -153,27 +155,7 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP self.handle_temp_hum_control() return flask.jsonify(success=True) - @octoprint.plugin.BlueprintPlugin.route("/clearGPIOMode", methods=["GET"]) - def clear_gpio_mode(self): - GPIO.cleanup() - return flask.jsonify(success=True) - - @octoprint.plugin.BlueprintPlugin.route("/updateUI", methods=["GET"]) - def update_ui_requested(self): - self.update_ui() - return flask.jsonify(success=True) - - @octoprint.plugin.BlueprintPlugin.route("/getOutputStatus", methods=["GET"]) - def get_output_status(self): - gpio_status = [] - for rpi_output in self.rpi_outputs: - if rpi_output['output_type'] == 'regular': - pin = self.to_int(rpi_output['gpio_pin']) - val = GPIO.input(pin) if not rpi_output['active_low'] else (not GPIO.input(pin)) - index = self.to_int(rpi_output['index_id']) - gpio_status.append(dict(index_id=index, status=val)) - return flask.Response(json.dumps(gpio_status), mimetype='application/json') - + ## GET /temperature/$id might as well also GET /temperature @octoprint.plugin.BlueprintPlugin.route("/getTemperatureStatus", methods=["GET"]) def get_temperature_status(self): temperature_status = [] @@ -186,6 +168,32 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP temperature_status.append(dict(index_id=index, label=label, temperature=temperature, humidity=humidity)) return flask.Response(json.dumps(temperature_status), mimetype='application/json') + ## POST /clear + @octoprint.plugin.BlueprintPlugin.route("/clearGPIOMode", methods=["GET"]) + def clear_gpio_mode(self): + GPIO.cleanup() + return flask.jsonify(success=True) + + ## POST /update + @octoprint.plugin.BlueprintPlugin.route("/updateUI", methods=["GET"]) + def update_ui_requested(self): + self.update_ui() + return flask.jsonify(success=True) + + ## GET /output/$id might as well also GET /output + @octoprint.plugin.BlueprintPlugin.route("/getOutputStatus", methods=["GET"]) + def get_output_status(self): + gpio_status = [] + for rpi_output in self.rpi_outputs: + if rpi_output['output_type'] == 'regular': + pin = self.to_int(rpi_output['gpio_pin']) + val = GPIO.input(pin) if not rpi_output['active_low'] else (not GPIO.input(pin)) + index = self.to_int(rpi_output['index_id']) + gpio_status.append(dict(index_id=index, status=val)) + return flask.Response(json.dumps(gpio_status), mimetype='application/json') + + ## POST /output/$id + ## maybe PATCH will be the more official way to do. Feedback? @octoprint.plugin.BlueprintPlugin.route("/setIO", methods=["GET"]) def set_io(self): index = flask.request.values["index_id"] @@ -196,6 +204,7 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP self.write_gpio(self.to_int(rpi_output['gpio_pin']), val) return flask.jsonify(success=True) + ## POST /shell @octoprint.plugin.BlueprintPlugin.route("/sendShellCommand", methods=["GET"]) def send_shell_command(self): output_index = self.to_int(flask.request.values["index_id"]) @@ -206,6 +215,8 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP self.shell_command(command) return flask.jsonify(success=True) + ## Possibly include this into POST/PATCH /output/$id and make it into the JSON body? + ## or maybe PATCH/POST /output/$id/auto-startup @octoprint.plugin.BlueprintPlugin.route("/setAutoStartUp", methods=["GET"]) def set_auto_startup(self): index = flask.request.values["index_id"] @@ -222,6 +233,7 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP self._settings.set(["rpi_outputs"], self.rpi_outputs) return flask.jsonify(success=True) + ## same as AutoStartup? @octoprint.plugin.BlueprintPlugin.route("/setAutoShutdown", methods=["GET"]) def set_auto_shutdown(self): index = flask.request.values["index_id"] @@ -239,6 +251,8 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP self._settings.set(["rpi_outputs"], self.rpi_outputs) return flask.jsonify(success=True) + ## POST filament/$id + ## maybe think of a GET for this as well @octoprint.plugin.BlueprintPlugin.route("/setFilamentSensor", methods=["GET"]) def set_filament_sensor(self): index = flask.request.values["index_id"] @@ -250,6 +264,7 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP self._settings.set(["rpi_inputs"], self.rpi_inputs) return flask.jsonify(success=True) + ## POST pwm/$id @octoprint.plugin.BlueprintPlugin.route("/setPWM", methods=["GET"]) def set_pwm(self): set_value = self.to_int(flask.request.values["new_duty_cycle"]) @@ -261,6 +276,8 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP self.write_pwm(gpio, set_value) return flask.jsonify(success=True) + ## POST gcode/$id + ## I think id might not even be needed here @octoprint.plugin.BlueprintPlugin.route("/sendGcodeCommand", methods=["GET"]) def requested_gcode_command(self): gpio_index = self.to_int(flask.request.values["index_id"]) @@ -268,6 +285,7 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP self.send_gcode_command(rpi_output['gcode']) return flask.jsonify(success=True) + ## POST neopixel/$id @octoprint.plugin.BlueprintPlugin.route("/setNeopixel", methods=["GET"]) def set_neopixel(self): """ set_neopixel method get request from octoprint and send the command to arduino or neopixel""" @@ -288,6 +306,7 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP return flask.jsonify(success=True) + ## POST rgb-led/$id @octoprint.plugin.BlueprintPlugin.route("/setLedstripColor", methods=["GET"]) def set_ledstrip_color(self): """ set_ledstrip_color method get request from octoprint and send the command to Open-Smart RGB LED Strip""" @@ -1363,7 +1382,6 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP queue_id = '{0!s}_{1!s}'.format(index_id, sufix) - self._logger.debug("Scheduling neopixel output id %s for on %s delay_seconds", queue_id, delay_seconds) thread = threading.Timer(delay_seconds, self.send_neopixel_command, From 5023e08c77574a18b0039634629b244ac44569d1 Mon Sep 17 00:00:00 2001 From: UnchartedBull Date: Wed, 9 Oct 2019 15:04:04 +0200 Subject: [PATCH 04/14] started changing first apis --- .gitignore | 2 + octoprint_enclosure/__init__.py | 228 ++++++++++++++++++++++++++++++-- 2 files changed, 219 insertions(+), 11 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e75ccaa --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +venv +.vscode diff --git a/octoprint_enclosure/__init__.py b/octoprint_enclosure/__init__.py index e786d5d..c49f0cf 100644 --- a/octoprint_enclosure/__init__.py +++ b/octoprint_enclosure/__init__.py @@ -7,6 +7,8 @@ from .ledstrip import LEDStrip import octoprint.plugin import RPi.GPIO as GPIO import flask +from flask import jsonify, request, make_response, Response +from werkzeug.exceptions import BadRequest import time import sys import glob @@ -159,7 +161,7 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP @octoprint.plugin.BlueprintPlugin.route("/getTemperatureStatus", methods=["GET"]) def get_temperature_status(self): temperature_status = [] - for rpi_input in self.rpi_input: + for rpi_input in self.rpi_inputs: if rpi_input['input_type'] == 'temperature_sensor': temperature = self.to_int(rpi_input['temp_sensor_temp']) humidity = self.to_int(rpi_input['temp_sensor_humidity']) @@ -253,8 +255,211 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP ## POST filament/$id ## maybe think of a GET for this as well + @octoprint.plugin.BlueprintPlugin.route("/filament/", methods=["PATCH"]) + def set_filament_sensor(self, identifier): + if "application/json" not in request.headers["Content-Type"]: + return make_response("expected json", 400) + try: + data = request.json + except BadRequest: + return make_response("malformed request", 400) + + if 'status' not in data: + return make_response("missing status attribute", 406) + + value = data["status"] + + for sensor in self.rpi_inputs: + if identifier == self.to_int(sensor['index_id']): + sensor['filament_sensor_enabled'] = value + self._logger.info("Setting filament sensor for input %s to : %s", identifier, value) + self._settings.set(["rpi_inputs"], self.rpi_inputs) + return make_response('', 204) + + @octoprint.plugin.BlueprintPlugin.route("/filament/", methods=["GET"]) + def get_filament_sensor(self, identifier): + for sensor in self.rpi_inputs: + if identifier == self.to_int(sensor['index_id']): + return jsonify(sensor) + return make_response('', 404) + + @octoprint.plugin.BlueprintPlugin.route("/pwm/", methods=["PATCH"]) + def set_pwm(self, identifier): + if "application/json" not in request.headers["Content-Type"]: + return make_response("expected json", 400) + try: + data = request.json + except BadRequest: + return make_response("malformed request", 400) + + if 'dutyCycle' not in data: + return make_response("missing dutyCycle attribute", 406) + + set_value = self.to_int(data['dutyCycle']) + for rpi_output in [item for item in self.rpi_outputs if item['index_id'] == identifier]: + rpi_output['duty_cycle'] = set_value + rpi_output['new_duty_cycle'] = "" + gpio = self.to_int(rpi_output['gpio_pin']) + self.write_pwm(gpio, set_value) + return make_response('', 204) + + @octoprint.plugin.BlueprintPlugin.route("/gcode/", methods=["POST"]) + def requested_gcode_command(self, identifier): + rpi_output = [r_out for r_out in self.rpi_outputs if self.to_int(r_out['index_id']) == identifier].pop() + self.send_gcode_command(rpi_output['gcode']) + return make_response('', 204) + + @octoprint.plugin.BlueprintPlugin.route("/neopixel/", methods=["PATCH"]) + def set_neopixel(self, identifier): + """ set_neopixel method get request from octoprint and send the command to arduino or neopixel""" + if "application/json" not in request.headers["Content-Type"]: + return make_response("expected json", 400) + try: + data = request.json + except BadRequest: + return make_response("malformed request", 400) + + if 'red' not in data: + return make_response("missing red attribute", 406) + if 'green' not in data: + return make_response("missing green attribute", 406) + if 'blue' not in data: + return make_response("missing blue attribute", 406) + + red = data['red'] + green = data['green'] + blue = data['blue'] + + for rpi_output in self.rpi_outputs: + if identifier == self.to_int(rpi_output['index_id']): + led_count = rpi_output['neopixel_count'] + led_brightness = rpi_output['neopixel_brightness'] + address = rpi_output['microcontroller_address'] + + neopixel_dirrect = rpi_output['output_type'] == 'neopixel_direct' + + self.send_neopixel_command(self.to_int(rpi_output['gpio_pin']), led_count, led_brightness, red, green, + blue, address, neopixel_dirrect, identifier) + + return make_response('', 204) + + @octoprint.plugin.BlueprintPlugin.route("/rgb-led/", methods=["PATCH"]) + def set_ledstrip_color(self, identifier): + """ set_ledstrip_color method get request from octoprint and send the command to Open-Smart RGB LED Strip""" + if "application/json" not in request.headers["Content-Type"]: + return make_response("expected json", 400) + try: + data = request.json + except BadRequest: + return make_response("malformed request", 400) + + if 'rgb' not in data: + return make_response("missing rgb attribute", 406) + rgb = data['rgb'] + + for rpi_output in self.rpi_outputs: + if identifier == self.to_int(rpi_output['index_id']): + self.ledstrip_set_rgb(rpi_output, rgb) + + return make_response('', 204) + + + + + + """ + DEPRECATION + This API will be deprecated in a future version + """ + + # ~~ Blueprintplugin mixin + @octoprint.plugin.BlueprintPlugin.route("/setEnclosureTempHum", methods=["GET"]) + def set_enclosure_temp_humidity_old(self): + set_value = self.to_float(flask.request.values["set_temperature"]) + index_id = self.to_int(flask.request.values["index_id"]) + + for temp_hum_control in [item for item in self.rpi_outputs if item['index_id'] == index_id]: + temp_hum_control['temp_ctr_set_value'] = set_value + + self.handle_temp_hum_control() + return flask.jsonify(success=True) + + @octoprint.plugin.BlueprintPlugin.route("/clearGPIOMode", methods=["GET"]) + def clear_gpio_mode_old(self): + GPIO.cleanup() + return flask.jsonify(success=True) + + @octoprint.plugin.BlueprintPlugin.route("/updateUI", methods=["GET"]) + def update_ui_requested_old(self): + self.update_ui() + return flask.jsonify(success=True) + + @octoprint.plugin.BlueprintPlugin.route("/getOutputStatus", methods=["GET"]) + def get_output_status_old(self): + gpio_status = [] + for rpi_output in self.rpi_outputs: + if rpi_output['output_type'] == 'regular': + pin = self.to_int(rpi_output['gpio_pin']) + val = GPIO.input(pin) if not rpi_output['active_low'] else (not GPIO.input(pin)) + index = self.to_int(rpi_output['index_id']) + gpio_status.append(dict(index_id=index, status=val)) + return flask.Response(json.dumps(gpio_status), mimetype='application/json') + + @octoprint.plugin.BlueprintPlugin.route("/setIO", methods=["GET"]) + def set_io_old(self): + index = flask.request.values["index_id"] + value = True if flask.request.values["status"] == 'true' else False + for rpi_output in self.rpi_outputs: + if self.to_int(index) == self.to_int(rpi_output['index_id']): + val = (not value) if rpi_output['active_low'] else value + 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_shell_command_old(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() + + command = rpi_output['shell_script'] + self.shell_command(command) + return flask.jsonify(success=True) + + @octoprint.plugin.BlueprintPlugin.route("/setAutoStartUp", methods=["GET"]) + def set_auto_startup_old(self): + index = flask.request.values["index_id"] + value = True if flask.request.values["status"] == 'true' else False + + if not value: + suffix = 'auto_startup' + queue_id = '{0!s}_{1!s}'.format(index, suffix) + self.stop_queue_item(queue_id) + for output in self.rpi_outputs: + if self.to_int(index) == self.to_int(output['index_id']): + output['auto_startup'] = value + self._logger.info("Setting auto startup for output %s to : %s", index, value) + self._settings.set(["rpi_outputs"], self.rpi_outputs) + return flask.jsonify(success=True) + + @octoprint.plugin.BlueprintPlugin.route("/setAutoShutdown", methods=["GET"]) + def set_auto_shutdown_old(self): + index = flask.request.values["index_id"] + value = True if flask.request.values["status"] == 'true' else False + + if not value: + suffix = 'auto_shutdown' + queue_id = '{0!s}_{1!s}'.format(index, suffix) + self.stop_queue_item(queue_id) + + for output in self.rpi_outputs: + if self.to_int(index) == self.to_int(output['index_id']): + output['auto_shutdown'] = value + self._logger.info("Setting auto shutdown for output %s to : %s", index, value) + self._settings.set(["rpi_outputs"], self.rpi_outputs) + return flask.jsonify(success=True) + @octoprint.plugin.BlueprintPlugin.route("/setFilamentSensor", methods=["GET"]) - def set_filament_sensor(self): + def set_filament_sensor_old(self): index = flask.request.values["index_id"] value = True if flask.request.values["status"] == 'true' else False for sensor in self.rpi_inputs: @@ -264,9 +469,8 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP self._settings.set(["rpi_inputs"], self.rpi_inputs) return flask.jsonify(success=True) - ## POST pwm/$id @octoprint.plugin.BlueprintPlugin.route("/setPWM", methods=["GET"]) - def set_pwm(self): + def set_pwm_old(self): set_value = self.to_int(flask.request.values["new_duty_cycle"]) index_id = self.to_int(flask.request.values["index_id"]) for rpi_output in [item for item in self.rpi_outputs if item['index_id'] == index_id]: @@ -276,18 +480,15 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP self.write_pwm(gpio, set_value) return flask.jsonify(success=True) - ## POST gcode/$id - ## I think id might not even be needed here @octoprint.plugin.BlueprintPlugin.route("/sendGcodeCommand", methods=["GET"]) - def requested_gcode_command(self): + def requested_gcode_command_old(self): gpio_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']) == gpio_index].pop() self.send_gcode_command(rpi_output['gcode']) return flask.jsonify(success=True) - ## POST neopixel/$id @octoprint.plugin.BlueprintPlugin.route("/setNeopixel", methods=["GET"]) - def set_neopixel(self): + def set_neopixel_old(self): """ set_neopixel method get request from octoprint and send the command to arduino or neopixel""" gpio_index = self.to_int(flask.request.values["index_id"]) red = flask.request.values["red"] @@ -306,9 +507,8 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP return flask.jsonify(success=True) - ## POST rgb-led/$id @octoprint.plugin.BlueprintPlugin.route("/setLedstripColor", methods=["GET"]) - def set_ledstrip_color(self): + def set_ledstrip_color_old(self): """ set_ledstrip_color method get request from octoprint and send the command to Open-Smart RGB LED Strip""" gpio_index = self.to_int(flask.request.values["index_id"]) rgb = flask.request.values["rgb"] @@ -318,6 +518,12 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP return flask.jsonify(success=True) + # DEPREACTION END + + + + + 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 From 0601d165591fb844976a70fe5e9f8f42e4bcec33 Mon Sep 17 00:00:00 2001 From: UnchartedBull Date: Wed, 9 Oct 2019 17:11:33 +0200 Subject: [PATCH 05/14] rewrote API to be kind of RESTful --- octoprint_enclosure/__init__.py | 247 ++++++++++++++++++-------------- 1 file changed, 142 insertions(+), 105 deletions(-) diff --git a/octoprint_enclosure/__init__.py b/octoprint_enclosure/__init__.py index c49f0cf..7dc784d 100644 --- a/octoprint_enclosure/__init__.py +++ b/octoprint_enclosure/__init__.py @@ -144,46 +144,56 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP self.rpi_inputs = self._settings.get(["rpi_inputs"]) # ~~ Blueprintplugin mixin - ## POST /temperature/$id - ## maybe PATCH will be the more official way to do. Feedback? - @octoprint.plugin.BlueprintPlugin.route("/setEnclosureTempHum", methods=["GET"]) - def set_enclosure_temp_humidity(self): - set_value = self.to_float(flask.request.values["set_temperature"]) - index_id = self.to_int(flask.request.values["index_id"]) - - for temp_hum_control in [item for item in self.rpi_outputs if item['index_id'] == index_id]: - temp_hum_control['temp_ctr_set_value'] = set_value - - self.handle_temp_hum_control() - return flask.jsonify(success=True) - - ## GET /temperature/$id might as well also GET /temperature - @octoprint.plugin.BlueprintPlugin.route("/getTemperatureStatus", methods=["GET"]) + @octoprint.plugin.BlueprintPlugin.route("/temperature", methods=["GET"]) def get_temperature_status(self): temperature_status = [] for rpi_input in self.rpi_inputs: if rpi_input['input_type'] == 'temperature_sensor': - temperature = self.to_int(rpi_input['temp_sensor_temp']) - humidity = self.to_int(rpi_input['temp_sensor_humidity']) + temperature = self.to_float(rpi_input['temp_sensor_temp']) + humidity = self.to_float(rpi_input['temp_sensor_humidity']) index = self.to_int(rpi_input['index_id']) label = rpi_input['label'] temperature_status.append(dict(index_id=index, label=label, temperature=temperature, humidity=humidity)) - return flask.Response(json.dumps(temperature_status), mimetype='application/json') + return jsonify(temperature_status) - ## POST /clear - @octoprint.plugin.BlueprintPlugin.route("/clearGPIOMode", methods=["GET"]) + @octoprint.plugin.BlueprintPlugin.route("/temperature/", methods=["GET"]) + def get_single_temperature_status(self, identifier): + for rpi_input in self.rpi_inputs: + if identifier == self.to_int(rpi_input['index_id']): + return jsonify(rpi_input) + return make_response('', 404) + + @octoprint.plugin.BlueprintPlugin.route("/temperature/", methods=["PATCH"]) + def set_enclosure_temp_humidity(self, identifier): + if "application/json" not in request.headers["Content-Type"]: + return make_response("expected json", 400) + try: + data = request.json + except BadRequest: + return make_response("malformed request", 400) + + if 'temperature' not in data: + return make_response("missing temperature attribute", 406) + + set_value = data["temperature"] + + for temp_hum_control in [item for item in self.rpi_outputs if item['index_id'] == identifier]: + temp_hum_control['temp_ctr_set_value'] = set_value + + self.handle_temp_hum_control() + return make_response('', 204) + + @octoprint.plugin.BlueprintPlugin.route("/clear-gpio", methods=["POST"]) def clear_gpio_mode(self): GPIO.cleanup() - return flask.jsonify(success=True) + return make_response('', 204) - ## POST /update - @octoprint.plugin.BlueprintPlugin.route("/updateUI", methods=["GET"]) + @octoprint.plugin.BlueprintPlugin.route("/update", methods=["POST"]) def update_ui_requested(self): self.update_ui() - return flask.jsonify(success=True) + return make_response('', 204) - ## GET /output/$id might as well also GET /output - @octoprint.plugin.BlueprintPlugin.route("/getOutputStatus", methods=["GET"]) + @octoprint.plugin.BlueprintPlugin.route("/output", methods=["GET"]) def get_output_status(self): gpio_status = [] for rpi_output in self.rpi_outputs: @@ -192,69 +202,103 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP val = GPIO.input(pin) if not rpi_output['active_low'] else (not GPIO.input(pin)) index = self.to_int(rpi_output['index_id']) gpio_status.append(dict(index_id=index, status=val)) - return flask.Response(json.dumps(gpio_status), mimetype='application/json') + return jsonify(gpio_status) - ## POST /output/$id - ## maybe PATCH will be the more official way to do. Feedback? - @octoprint.plugin.BlueprintPlugin.route("/setIO", methods=["GET"]) - def set_io(self): - index = flask.request.values["index_id"] - value = True if flask.request.values["status"] == 'true' else False + @octoprint.plugin.BlueprintPlugin.route("/output/", methods=["GET"]) + def get_single_output_status(self, identifier): for rpi_output in self.rpi_outputs: - if self.to_int(index) == self.to_int(rpi_output['index_id']): + if identifier == self.to_int(rpi_output['index_id']): + return jsonify(rpi_output) + return make_response('', 404) + + @octoprint.plugin.BlueprintPlugin.route("/output/", methods=["PATCH"]) + def set_io(self, identifier): + if "application/json" not in request.headers["Content-Type"]: + return make_response("expected json", 400) + try: + data = request.json + except BadRequest: + return make_response("malformed request", 400) + + if 'status' not in data: + return make_response("missing status attribute", 406) + + value = data["status"] + + for rpi_output in self.rpi_outputs: + if identifier == self.to_int(rpi_output['index_id']): val = (not value) if rpi_output['active_low'] else value self.write_gpio(self.to_int(rpi_output['gpio_pin']), val) - return flask.jsonify(success=True) + return make_response('', 204) - ## POST /shell - @octoprint.plugin.BlueprintPlugin.route("/sendShellCommand", methods=["GET"]) - def 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() + @octoprint.plugin.BlueprintPlugin.route("/shell/", methods=["POST"]) + def send_shell_command(self, identifier): + rpi_output = [r_out for r_out in self.rpi_outputs if self.to_int(r_out['index_id']) == identifier].pop() command = rpi_output['shell_script'] self.shell_command(command) - return flask.jsonify(success=True) + return make_response('', 204) - ## Possibly include this into POST/PATCH /output/$id and make it into the JSON body? - ## or maybe PATCH/POST /output/$id/auto-startup - @octoprint.plugin.BlueprintPlugin.route("/setAutoStartUp", methods=["GET"]) - def set_auto_startup(self): - index = flask.request.values["index_id"] - value = True if flask.request.values["status"] == 'true' else False + @octoprint.plugin.BlueprintPlugin.route("/output//auto-startup", methods=["PATCH"]) + def set_auto_startup(self, identifier): + if "application/json" not in request.headers["Content-Type"]: + return make_response("expected json", 400) + try: + data = request.json + except BadRequest: + return make_response("malformed request", 400) + + if 'status' not in data: + return make_response("missing status attribute", 406) + + value = data["status"] if not value: suffix = 'auto_startup' - queue_id = '{0!s}_{1!s}'.format(index, suffix) + queue_id = '{0!s}_{1!s}'.format(str(identifier), suffix) self.stop_queue_item(queue_id) for output in self.rpi_outputs: - if self.to_int(index) == self.to_int(output['index_id']): + if identifier == self.to_int(output['index_id']): output['auto_startup'] = value - self._logger.info("Setting auto startup for output %s to : %s", index, value) + self._logger.info("Setting auto startup for output %s to : %s", str(identifier), value) self._settings.set(["rpi_outputs"], self.rpi_outputs) - return flask.jsonify(success=True) + return make_response('', 204) - ## same as AutoStartup? - @octoprint.plugin.BlueprintPlugin.route("/setAutoShutdown", methods=["GET"]) - def set_auto_shutdown(self): - index = flask.request.values["index_id"] - value = True if flask.request.values["status"] == 'true' else False + @octoprint.plugin.BlueprintPlugin.route("/output//auto-shutdown", methods=["PATCH"]) + def set_auto_shutdown(self, identifier): + if "application/json" not in request.headers["Content-Type"]: + return make_response("expected json", 400) + try: + data = request.json + except BadRequest: + return make_response("malformed request", 400) + + if 'status' not in data: + return make_response("missing status attribute", 406) + + value = data["status"] if not value: suffix = 'auto_shutdown' - queue_id = '{0!s}_{1!s}'.format(index, suffix) + queue_id = '{0!s}_{1!s}'.format(str(identifier), suffix) self.stop_queue_item(queue_id) for output in self.rpi_outputs: - if self.to_int(index) == self.to_int(output['index_id']): + if identifier == self.to_int(output['index_id']): output['auto_shutdown'] = value - self._logger.info("Setting auto shutdown for output %s to : %s", index, value) + self._logger.info("Setting auto shutdown for output %s to : %s", str(identifier), value) self._settings.set(["rpi_outputs"], self.rpi_outputs) - return flask.jsonify(success=True) + return make_response('', 204) + + @octoprint.plugin.BlueprintPlugin.route("/filament/", methods=["GET"]) + def get_filament_sensor(self, identifier): + for sensor in self.rpi_inputs: + if identifier == self.to_int(sensor['index_id']): + return jsonify(sensor) + return make_response('', 404) + + # TODO: maybe get all filament sensors via GET /filament. What would be they correct type here? - ## POST filament/$id - ## maybe think of a GET for this as well @octoprint.plugin.BlueprintPlugin.route("/filament/", methods=["PATCH"]) def set_filament_sensor(self, identifier): if "application/json" not in request.headers["Content-Type"]: @@ -272,17 +316,10 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP for sensor in self.rpi_inputs: if identifier == self.to_int(sensor['index_id']): sensor['filament_sensor_enabled'] = value - self._logger.info("Setting filament sensor for input %s to : %s", identifier, value) + self._logger.info("Setting filament sensor for input %s to : %s", str(identifier), value) self._settings.set(["rpi_inputs"], self.rpi_inputs) return make_response('', 204) - @octoprint.plugin.BlueprintPlugin.route("/filament/", methods=["GET"]) - def get_filament_sensor(self, identifier): - for sensor in self.rpi_inputs: - if identifier == self.to_int(sensor['index_id']): - return jsonify(sensor) - return make_response('', 404) - @octoprint.plugin.BlueprintPlugin.route("/pwm/", methods=["PATCH"]) def set_pwm(self, identifier): if "application/json" not in request.headers["Content-Type"]: @@ -375,24 +412,24 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP # ~~ Blueprintplugin mixin @octoprint.plugin.BlueprintPlugin.route("/setEnclosureTempHum", methods=["GET"]) def set_enclosure_temp_humidity_old(self): - set_value = self.to_float(flask.request.values["set_temperature"]) - index_id = self.to_int(flask.request.values["index_id"]) + set_value = self.to_float(request.values["set_temperature"]) + index_id = self.to_int(request.values["index_id"]) for temp_hum_control in [item for item in self.rpi_outputs if item['index_id'] == index_id]: temp_hum_control['temp_ctr_set_value'] = set_value self.handle_temp_hum_control() - return flask.jsonify(success=True) + return jsonify(success=True) @octoprint.plugin.BlueprintPlugin.route("/clearGPIOMode", methods=["GET"]) def clear_gpio_mode_old(self): GPIO.cleanup() - return flask.jsonify(success=True) + return jsonify(success=True) @octoprint.plugin.BlueprintPlugin.route("/updateUI", methods=["GET"]) def update_ui_requested_old(self): self.update_ui() - return flask.jsonify(success=True) + return jsonify(success=True) @octoprint.plugin.BlueprintPlugin.route("/getOutputStatus", methods=["GET"]) def get_output_status_old(self): @@ -403,32 +440,32 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP val = GPIO.input(pin) if not rpi_output['active_low'] else (not GPIO.input(pin)) index = self.to_int(rpi_output['index_id']) gpio_status.append(dict(index_id=index, status=val)) - return flask.Response(json.dumps(gpio_status), mimetype='application/json') + return Response(json.dumps(gpio_status), mimetype='application/json') @octoprint.plugin.BlueprintPlugin.route("/setIO", methods=["GET"]) def set_io_old(self): - index = flask.request.values["index_id"] - value = True if flask.request.values["status"] == 'true' else False + index = request.values["index_id"] + value = True if request.values["status"] == 'true' else False for rpi_output in self.rpi_outputs: if self.to_int(index) == self.to_int(rpi_output['index_id']): val = (not value) if rpi_output['active_low'] else value self.write_gpio(self.to_int(rpi_output['gpio_pin']), val) - return flask.jsonify(success=True) + return jsonify(success=True) @octoprint.plugin.BlueprintPlugin.route("/sendShellCommand", methods=["GET"]) def send_shell_command_old(self): - output_index = self.to_int(flask.request.values["index_id"]) + output_index = self.to_int(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() command = rpi_output['shell_script'] self.shell_command(command) - return flask.jsonify(success=True) + return jsonify(success=True) @octoprint.plugin.BlueprintPlugin.route("/setAutoStartUp", methods=["GET"]) def set_auto_startup_old(self): - index = flask.request.values["index_id"] - value = True if flask.request.values["status"] == 'true' else False + index = request.values["index_id"] + value = True if request.values["status"] == 'true' else False if not value: suffix = 'auto_startup' @@ -439,12 +476,12 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP output['auto_startup'] = value self._logger.info("Setting auto startup for output %s to : %s", index, value) self._settings.set(["rpi_outputs"], self.rpi_outputs) - return flask.jsonify(success=True) + return jsonify(success=True) @octoprint.plugin.BlueprintPlugin.route("/setAutoShutdown", methods=["GET"]) def set_auto_shutdown_old(self): - index = flask.request.values["index_id"] - value = True if flask.request.values["status"] == 'true' else False + index = request.values["index_id"] + value = True if request.values["status"] == 'true' else False if not value: suffix = 'auto_shutdown' @@ -456,44 +493,44 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP output['auto_shutdown'] = value self._logger.info("Setting auto shutdown for output %s to : %s", index, value) self._settings.set(["rpi_outputs"], self.rpi_outputs) - return flask.jsonify(success=True) + return jsonify(success=True) @octoprint.plugin.BlueprintPlugin.route("/setFilamentSensor", methods=["GET"]) def set_filament_sensor_old(self): - index = flask.request.values["index_id"] - value = True if flask.request.values["status"] == 'true' else False + index = request.values["index_id"] + value = True if request.values["status"] == 'true' else False for sensor in self.rpi_inputs: if self.to_int(index) == self.to_int(sensor['index_id']): sensor['filament_sensor_enabled'] = value self._logger.info("Setting filament sensor for input %s to : %s", index, value) self._settings.set(["rpi_inputs"], self.rpi_inputs) - return flask.jsonify(success=True) + return jsonify(success=True) @octoprint.plugin.BlueprintPlugin.route("/setPWM", methods=["GET"]) def set_pwm_old(self): - set_value = self.to_int(flask.request.values["new_duty_cycle"]) - index_id = self.to_int(flask.request.values["index_id"]) + set_value = self.to_int(request.values["new_duty_cycle"]) + index_id = self.to_int(request.values["index_id"]) for rpi_output in [item for item in self.rpi_outputs if item['index_id'] == index_id]: rpi_output['duty_cycle'] = set_value rpi_output['new_duty_cycle'] = "" gpio = self.to_int(rpi_output['gpio_pin']) self.write_pwm(gpio, set_value) - return flask.jsonify(success=True) + return jsonify(success=True) @octoprint.plugin.BlueprintPlugin.route("/sendGcodeCommand", methods=["GET"]) def requested_gcode_command_old(self): - gpio_index = self.to_int(flask.request.values["index_id"]) + gpio_index = self.to_int(request.values["index_id"]) rpi_output = [r_out for r_out in self.rpi_outputs if self.to_int(r_out['index_id']) == gpio_index].pop() self.send_gcode_command(rpi_output['gcode']) - return flask.jsonify(success=True) + return jsonify(success=True) @octoprint.plugin.BlueprintPlugin.route("/setNeopixel", methods=["GET"]) def set_neopixel_old(self): """ set_neopixel method get request from octoprint and send the command to arduino or neopixel""" - gpio_index = self.to_int(flask.request.values["index_id"]) - red = flask.request.values["red"] - green = flask.request.values["green"] - blue = flask.request.values["blue"] + gpio_index = self.to_int(request.values["index_id"]) + red = request.values["red"] + green = request.values["green"] + blue = request.values["blue"] for rpi_output in self.rpi_outputs: if gpio_index == self.to_int(rpi_output['index_id']): led_count = rpi_output['neopixel_count'] @@ -505,18 +542,18 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP self.send_neopixel_command(self.to_int(rpi_output['gpio_pin']), led_count, led_brightness, red, green, blue, address, neopixel_dirrect, gpio_index) - return flask.jsonify(success=True) + return jsonify(success=True) @octoprint.plugin.BlueprintPlugin.route("/setLedstripColor", methods=["GET"]) def set_ledstrip_color_old(self): """ set_ledstrip_color method get request from octoprint and send the command to Open-Smart RGB LED Strip""" - gpio_index = self.to_int(flask.request.values["index_id"]) - rgb = flask.request.values["rgb"] + gpio_index = self.to_int(request.values["index_id"]) + rgb = request.values["rgb"] for rpi_output in self.rpi_outputs: if gpio_index == self.to_int(rpi_output['index_id']): self.ledstrip_set_rgb(rpi_output, rgb) - return flask.jsonify(success=True) + return jsonify(success=True) # DEPREACTION END @@ -1395,7 +1432,7 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP self._logger.info("Error: Too many redirects") except requests.exceptions.RequestException as reqe: self._logger.info("Error: {e}".format(e=reqe)) - if res.status_code != requests.codes.ok: + if res.status_code != requests.codes['ok']: try: j = res.json() except ValueError: From b62235af1581e211b7d960f4920feb826becc354 Mon Sep 17 00:00:00 2001 From: UnchartedBull Date: Wed, 9 Oct 2019 17:17:37 +0200 Subject: [PATCH 06/14] remove flask import --- octoprint_enclosure/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/octoprint_enclosure/__init__.py b/octoprint_enclosure/__init__.py index 7dc784d..50ae142 100644 --- a/octoprint_enclosure/__init__.py +++ b/octoprint_enclosure/__init__.py @@ -6,7 +6,6 @@ from subprocess import Popen, PIPE from .ledstrip import LEDStrip import octoprint.plugin import RPi.GPIO as GPIO -import flask from flask import jsonify, request, make_response, Response from werkzeug.exceptions import BadRequest import time From 11897cdbbc5770c7bb4b875a3d4d2f12e9bc69fd Mon Sep 17 00:00:00 2001 From: UnchartedBull Date: Wed, 9 Oct 2019 22:28:17 +0200 Subject: [PATCH 07/14] Limit temperature outputs --- octoprint_enclosure/__init__.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/octoprint_enclosure/__init__.py b/octoprint_enclosure/__init__.py index 50ae142..3262fde 100644 --- a/octoprint_enclosure/__init__.py +++ b/octoprint_enclosure/__init__.py @@ -152,14 +152,25 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP humidity = self.to_float(rpi_input['temp_sensor_humidity']) index = self.to_int(rpi_input['index_id']) label = rpi_input['label'] - temperature_status.append(dict(index_id=index, label=label, temperature=temperature, humidity=humidity)) + temperature_status.append({'index_id': index, 'label': label, 'temperature': temperature, 'humidity': humidity}) return jsonify(temperature_status) @octoprint.plugin.BlueprintPlugin.route("/temperature/", methods=["GET"]) def get_single_temperature_status(self, identifier): for rpi_input in self.rpi_inputs: if identifier == self.to_int(rpi_input['index_id']): - return jsonify(rpi_input) + return jsonify({ + 'indexId': rpi_input['index_id'], + 'gpioPin': rpi_input['gpio_pin'], + 'type': rpi_input['temp_sensor_type'], + 'inputType': rpi_input['input_type'], + 'label': rpi_input['label'], + 'address': rpi_input['temp_sensor_address'], + 'humidity': self.to_float(rpi_input['temp_sensor_humidity']), + 'temperature': self.to_float(rpi_input['temp_sensor_temp']), + 'useFahrenheit': rpi_input['use_fahrenheit'], + 'showNavbar': rpi_input['temp_sensor_navbar'] + }) return make_response('', 404) @octoprint.plugin.BlueprintPlugin.route("/temperature/", methods=["PATCH"]) From 6c36d4b924d26c0143b49d3aa9964af04b9da777 Mon Sep 17 00:00:00 2001 From: UnchartedBull Date: Wed, 9 Oct 2019 22:39:41 +0200 Subject: [PATCH 08/14] First idea for new API concept --- octoprint_enclosure/__init__.py | 32 ++++++++------------------------ 1 file changed, 8 insertions(+), 24 deletions(-) diff --git a/octoprint_enclosure/__init__.py b/octoprint_enclosure/__init__.py index 3262fde..1d3c76e 100644 --- a/octoprint_enclosure/__init__.py +++ b/octoprint_enclosure/__init__.py @@ -143,34 +143,18 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP self.rpi_inputs = self._settings.get(["rpi_inputs"]) # ~~ Blueprintplugin mixin - @octoprint.plugin.BlueprintPlugin.route("/temperature", methods=["GET"]) - def get_temperature_status(self): - temperature_status = [] + @octoprint.plugin.BlueprintPlugin.route("/input", methods=["GET"]) + def get_inputs(self): + inputs = [] for rpi_input in self.rpi_inputs: - if rpi_input['input_type'] == 'temperature_sensor': - temperature = self.to_float(rpi_input['temp_sensor_temp']) - humidity = self.to_float(rpi_input['temp_sensor_humidity']) - index = self.to_int(rpi_input['index_id']) - label = rpi_input['label'] - temperature_status.append({'index_id': index, 'label': label, 'temperature': temperature, 'humidity': humidity}) - return jsonify(temperature_status) + inputs.append(dict(index_id=rpi_input['index_id'], label=rpi_input['label'])) + return jsonify(inputs) - @octoprint.plugin.BlueprintPlugin.route("/temperature/", methods=["GET"]) - def get_single_temperature_status(self, identifier): + @octoprint.plugin.BlueprintPlugin.route("/input/", methods=["GET"]) + def get_input_status(self, identifier): for rpi_input in self.rpi_inputs: if identifier == self.to_int(rpi_input['index_id']): - return jsonify({ - 'indexId': rpi_input['index_id'], - 'gpioPin': rpi_input['gpio_pin'], - 'type': rpi_input['temp_sensor_type'], - 'inputType': rpi_input['input_type'], - 'label': rpi_input['label'], - 'address': rpi_input['temp_sensor_address'], - 'humidity': self.to_float(rpi_input['temp_sensor_humidity']), - 'temperature': self.to_float(rpi_input['temp_sensor_temp']), - 'useFahrenheit': rpi_input['use_fahrenheit'], - 'showNavbar': rpi_input['temp_sensor_navbar'] - }) + return jsonify(rpi_input) return make_response('', 404) @octoprint.plugin.BlueprintPlugin.route("/temperature/", methods=["PATCH"]) From fad2581e016535009477f4bc45af21e9f8971890 Mon Sep 17 00:00:00 2001 From: UnchartedBull Date: Wed, 9 Oct 2019 23:16:01 +0200 Subject: [PATCH 09/14] should work now --- octoprint_enclosure/__init__.py | 99 ++++++++++++++++----------------- 1 file changed, 47 insertions(+), 52 deletions(-) diff --git a/octoprint_enclosure/__init__.py b/octoprint_enclosure/__init__.py index 1d3c76e..1203cf0 100644 --- a/octoprint_enclosure/__init__.py +++ b/octoprint_enclosure/__init__.py @@ -143,18 +143,20 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP self.rpi_inputs = self._settings.get(["rpi_inputs"]) # ~~ Blueprintplugin mixin - @octoprint.plugin.BlueprintPlugin.route("/input", methods=["GET"]) + @octoprint.plugin.BlueprintPlugin.route("/inputs", methods=["GET"]) def get_inputs(self): inputs = [] for rpi_input in self.rpi_inputs: - inputs.append(dict(index_id=rpi_input['index_id'], label=rpi_input['label'])) - return jsonify(inputs) + index = self.to_int(rpi_input['index_id']) + label = rpi_input['label'] + inputs.append(dict(index_id=index, label=label)) + return Response(json.dumps(inputs), mimetype='application/json') - @octoprint.plugin.BlueprintPlugin.route("/input/", methods=["GET"]) + @octoprint.plugin.BlueprintPlugin.route("/inputs/", methods=["GET"]) def get_input_status(self, identifier): for rpi_input in self.rpi_inputs: if identifier == self.to_int(rpi_input['index_id']): - return jsonify(rpi_input) + return Response(json.dumps(rpi_input), mimetype='application/json') return make_response('', 404) @octoprint.plugin.BlueprintPlugin.route("/temperature/", methods=["PATCH"]) @@ -177,32 +179,45 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP self.handle_temp_hum_control() return make_response('', 204) - @octoprint.plugin.BlueprintPlugin.route("/clear-gpio", methods=["POST"]) - def clear_gpio_mode(self): - GPIO.cleanup() + @octoprint.plugin.BlueprintPlugin.route("/filament/", methods=["PATCH"]) + def set_filament_sensor(self, identifier): + if "application/json" not in request.headers["Content-Type"]: + return make_response("expected json", 400) + try: + data = request.json + except BadRequest: + return make_response("malformed request", 400) + + if 'status' not in data: + return make_response("missing status attribute", 406) + + value = data["status"] + + for sensor in self.rpi_inputs: + if identifier == self.to_int(sensor['index_id']): + sensor['filament_sensor_enabled'] = value + self._logger.info("Setting filament sensor for input %s to : %s", str(identifier), value) + self._settings.set(["rpi_inputs"], self.rpi_inputs) return make_response('', 204) - @octoprint.plugin.BlueprintPlugin.route("/update", methods=["POST"]) - def update_ui_requested(self): - self.update_ui() - return make_response('', 204) - - @octoprint.plugin.BlueprintPlugin.route("/output", methods=["GET"]) - def get_output_status(self): + @octoprint.plugin.BlueprintPlugin.route("/outputs", methods=["GET"]) + def get_outputs(self): gpio_status = [] for rpi_output in self.rpi_outputs: if rpi_output['output_type'] == 'regular': - pin = self.to_int(rpi_output['gpio_pin']) - val = GPIO.input(pin) if not rpi_output['active_low'] else (not GPIO.input(pin)) index = self.to_int(rpi_output['index_id']) - gpio_status.append(dict(index_id=index, status=val)) - return jsonify(gpio_status) + label = rpi_output['label'] + gpio_status.append(dict(index_id=index, label=label)) + return Response(json.dumps(gpio_status), mimetype='application/json') - @octoprint.plugin.BlueprintPlugin.route("/output/", methods=["GET"]) - def get_single_output_status(self, identifier): + @octoprint.plugin.BlueprintPlugin.route("/outputs/", methods=["GET"]) + def get_output_status(self, identifier): for rpi_output in self.rpi_outputs: if identifier == self.to_int(rpi_output['index_id']): - return jsonify(rpi_output) + out = rpi_output.copy() + pin = self.to_int(rpi_output['gpio_pin']) + out['val'] = GPIO.input(pin) if not rpi_output['active_low'] else (not GPIO.input(pin)) + return Response(json.dumps(rpi_output), mimetype='application/json') return make_response('', 404) @octoprint.plugin.BlueprintPlugin.route("/output/", methods=["PATCH"]) @@ -225,6 +240,16 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP self.write_gpio(self.to_int(rpi_output['gpio_pin']), val) return make_response('', 204) + @octoprint.plugin.BlueprintPlugin.route("/clear-gpio", methods=["POST"]) + def clear_gpio_mode(self): + GPIO.cleanup() + return make_response('', 204) + + @octoprint.plugin.BlueprintPlugin.route("/update", methods=["POST"]) + def update_ui_requested(self): + self.update_ui() + return make_response('', 204) + @octoprint.plugin.BlueprintPlugin.route("/shell/", methods=["POST"]) def send_shell_command(self, identifier): rpi_output = [r_out for r_out in self.rpi_outputs if self.to_int(r_out['index_id']) == identifier].pop() @@ -284,36 +309,6 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP self._settings.set(["rpi_outputs"], self.rpi_outputs) return make_response('', 204) - @octoprint.plugin.BlueprintPlugin.route("/filament/", methods=["GET"]) - def get_filament_sensor(self, identifier): - for sensor in self.rpi_inputs: - if identifier == self.to_int(sensor['index_id']): - return jsonify(sensor) - return make_response('', 404) - - # TODO: maybe get all filament sensors via GET /filament. What would be they correct type here? - - @octoprint.plugin.BlueprintPlugin.route("/filament/", methods=["PATCH"]) - def set_filament_sensor(self, identifier): - if "application/json" not in request.headers["Content-Type"]: - return make_response("expected json", 400) - try: - data = request.json - except BadRequest: - return make_response("malformed request", 400) - - if 'status' not in data: - return make_response("missing status attribute", 406) - - value = data["status"] - - for sensor in self.rpi_inputs: - if identifier == self.to_int(sensor['index_id']): - sensor['filament_sensor_enabled'] = value - self._logger.info("Setting filament sensor for input %s to : %s", str(identifier), value) - self._settings.set(["rpi_inputs"], self.rpi_inputs) - return make_response('', 204) - @octoprint.plugin.BlueprintPlugin.route("/pwm/", methods=["PATCH"]) def set_pwm(self, identifier): if "application/json" not in request.headers["Content-Type"]: From f9e32d8e8b5fe02a37cd009468702547c314d9ad Mon Sep 17 00:00:00 2001 From: UnchartedBull Date: Wed, 9 Oct 2019 23:17:21 +0200 Subject: [PATCH 10/14] Rename --- octoprint_enclosure/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/octoprint_enclosure/__init__.py b/octoprint_enclosure/__init__.py index 1203cf0..26aa559 100644 --- a/octoprint_enclosure/__init__.py +++ b/octoprint_enclosure/__init__.py @@ -202,13 +202,13 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP @octoprint.plugin.BlueprintPlugin.route("/outputs", methods=["GET"]) def get_outputs(self): - gpio_status = [] + outputs = [] for rpi_output in self.rpi_outputs: if rpi_output['output_type'] == 'regular': index = self.to_int(rpi_output['index_id']) label = rpi_output['label'] - gpio_status.append(dict(index_id=index, label=label)) - return Response(json.dumps(gpio_status), mimetype='application/json') + outputs.append(dict(index_id=index, label=label)) + return Response(json.dumps(outputs), mimetype='application/json') @octoprint.plugin.BlueprintPlugin.route("/outputs/", methods=["GET"]) def get_output_status(self, identifier): From c54219fd1af8392dabb48beb8acd307e78fcbb0c Mon Sep 17 00:00:00 2001 From: UnchartedBull Date: Wed, 9 Oct 2019 23:42:14 +0200 Subject: [PATCH 11/14] correct naming plus restructuring --- octoprint_enclosure/__init__.py | 42 ++++++++++++++++----------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/octoprint_enclosure/__init__.py b/octoprint_enclosure/__init__.py index 26aa559..80759b9 100644 --- a/octoprint_enclosure/__init__.py +++ b/octoprint_enclosure/__init__.py @@ -220,7 +220,7 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP return Response(json.dumps(rpi_output), mimetype='application/json') return make_response('', 404) - @octoprint.plugin.BlueprintPlugin.route("/output/", methods=["PATCH"]) + @octoprint.plugin.BlueprintPlugin.route("/outputs/", methods=["PATCH"]) def set_io(self, identifier): if "application/json" not in request.headers["Content-Type"]: return make_response("expected json", 400) @@ -240,25 +240,7 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP self.write_gpio(self.to_int(rpi_output['gpio_pin']), val) return make_response('', 204) - @octoprint.plugin.BlueprintPlugin.route("/clear-gpio", methods=["POST"]) - def clear_gpio_mode(self): - GPIO.cleanup() - return make_response('', 204) - - @octoprint.plugin.BlueprintPlugin.route("/update", methods=["POST"]) - def update_ui_requested(self): - self.update_ui() - return make_response('', 204) - - @octoprint.plugin.BlueprintPlugin.route("/shell/", methods=["POST"]) - def send_shell_command(self, identifier): - rpi_output = [r_out for r_out in self.rpi_outputs if self.to_int(r_out['index_id']) == identifier].pop() - - command = rpi_output['shell_script'] - self.shell_command(command) - return make_response('', 204) - - @octoprint.plugin.BlueprintPlugin.route("/output//auto-startup", methods=["PATCH"]) + @octoprint.plugin.BlueprintPlugin.route("/outputs//auto-startup", methods=["PATCH"]) def set_auto_startup(self, identifier): if "application/json" not in request.headers["Content-Type"]: return make_response("expected json", 400) @@ -283,7 +265,7 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP self._settings.set(["rpi_outputs"], self.rpi_outputs) return make_response('', 204) - @octoprint.plugin.BlueprintPlugin.route("/output//auto-shutdown", methods=["PATCH"]) + @octoprint.plugin.BlueprintPlugin.route("/outputs//auto-shutdown", methods=["PATCH"]) def set_auto_shutdown(self, identifier): if "application/json" not in request.headers["Content-Type"]: return make_response("expected json", 400) @@ -309,6 +291,24 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP self._settings.set(["rpi_outputs"], self.rpi_outputs) return make_response('', 204) + @octoprint.plugin.BlueprintPlugin.route("/clear-gpio", methods=["POST"]) + def clear_gpio_mode(self): + GPIO.cleanup() + return make_response('', 204) + + @octoprint.plugin.BlueprintPlugin.route("/update", methods=["POST"]) + def update_ui_requested(self): + self.update_ui() + return make_response('', 204) + + @octoprint.plugin.BlueprintPlugin.route("/shell/", methods=["POST"]) + def send_shell_command(self, identifier): + rpi_output = [r_out for r_out in self.rpi_outputs if self.to_int(r_out['index_id']) == identifier].pop() + + command = rpi_output['shell_script'] + self.shell_command(command) + return make_response('', 204) + @octoprint.plugin.BlueprintPlugin.route("/pwm/", methods=["PATCH"]) def set_pwm(self, identifier): if "application/json" not in request.headers["Content-Type"]: From a9ef64eb23c379641d8a11a2cc8beb31e199d17d Mon Sep 17 00:00:00 2001 From: StefanCohen <33824565+StefanCohen@users.noreply.github.com> Date: Thu, 10 Oct 2019 00:40:43 +0200 Subject: [PATCH 12/14] First version of the new API documentation The new REST API documentation --- API.md | 169 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 169 insertions(+) create mode 100644 API.md diff --git a/API.md b/API.md new file mode 100644 index 0000000..4daf5ed --- /dev/null +++ b/API.md @@ -0,0 +1,169 @@ +# API Reference v2.0 + +## List all Inputs. + +Method: GET + +http:///plugin/enclosure/inputs?apikey= + +Response: + +``` +[ + { + "index_id": 1, + "label": "Input 1" + } +] +``` + + +## List a specific input. + +Method: GET + +http:///plugin/enclosure/inputs/1?apikey= + +Response: +``` +{ + "controlled_io": null, + "filament_sensor_timeout": 120, + "filament_sensor_enabled": true, + "temp_sensor_address": "", + "printer_action": "filament", + "controlled_io_set_value": "low", + "temp_sensor_type": "11", + "temp_sensor_navbar": true, + "temp_sensor_humidity": 19, + "edge": "fall", + "ds18b20_serial": "", + "action_type": "output_control", + "input_pull_resistor": "input_pull_up", + "input_type": "temperature_sensor", + "temp_sensor_temp": 33, + "label": "Input 1", + "index_id": 1, + "use_fahrenheit": false, + "gpio_pin": "4" +} +``` + +## List all outputs + +Method: GET + +http:///plugin/enclosure/outputs?apikey= + +Response: +``` +[ + { + "index_id": 1, + "label": "Ouput 1" + } +] +``` + +## List a specific output + +Method: GET + +http:///plugin/enclosure/outputs/1?apikey= + +Response: +``` +{ + "linked_temp_sensor": "", + "ledstrip_gpio_dat": "", + "startup_time": 0, + "temp_ctr_deadband": 0, + "neopixel_brightness": 255, + "new_duty_cycle": "", + "gpio_pin": 0, + "default_duty_cycle": 0, + "neopixel_color": "rgb(0,0,0)", + "hide_btn_ui": false, + "temp_ctr_set_value": 0, + "temp_ctr_default_value": 0, + "default_neopixel_color": "", + "controlled_io_set_value": "Low", + "auto_shutdown": false, + "shell_script": "", + "label": "Ouput 1", + "default_ledstrip_color": "", + "duty_a": 0, + "toggle_timer_off": 0, + "alarm_set_temp": 0, + "ledstrip_gpio_clk": "", + "auto_startup": false, + "controlled_io": 0, + "shutdown_time": 0, + "temp_ctr_type": "heater", + "gcode": "M117 Test", + "shutdown_on_failed": false, + "temperature_b": 0, + "ledstrip_color": "rgb(0,0,0)", + "temperature_a": 0, + "neopixel_count": 0, + "duty_cycle": 0, + "toggle_timer_on": 0, + "show_on_navbar": false, + "duty_b": 0, + "toggle_timer": false, + "pwm_status": 50, + "gpio_status": false, + "pwm_frequency": 50, + "new_ledstrip_color": "", + "startup_with_server": true, + "active_low": true, + "temp_ctr_max_temp": 0, + "pwm_temperature_linked": false, + "temp_ctr_new_set_value": "", + "output_type": "regular", + "microcontroller_address": 0, + "index_id": 1, + "new_neopixel_color": "" +} +``` + +## Enable/Disable Output: + +http:///plugin/enclosure/outputs/1?apikey= + +Method: PATCH +Content-Type: application/json +Body: { "status": boolean } + +example: +``` +{ "status": true } +``` + + +## Enable/Disable Output auto-shutdown: + +http:///plugin/enclosure/outputs/1/auto-shutdown?apikey= + +Method: PATCH +Content-Type: application/json +Body: { "status": boolean } + +example: +``` +{ "status": true } +``` + + +## Enable/Disable Output auto-shutdown: + +http:///plugin/enclosure/outputs/1/auto-startup?apikey= + +Method: PATCH +Content-Type: application/json +Body: { "status": boolean } + +example: +``` +{ "status": true } +``` From 893fb11463db940b137b84ae48b9213a22c4b185 Mon Sep 17 00:00:00 2001 From: UnchartedBull Date: Thu, 10 Oct 2019 15:29:48 +0200 Subject: [PATCH 13/14] Update docs --- API.md | 389 +++++++++++++++++++++++--------- octoprint_enclosure/__init__.py | 105 +++++---- 2 files changed, 347 insertions(+), 147 deletions(-) diff --git a/API.md b/API.md index 4daf5ed..e5ce300 100644 --- a/API.md +++ b/API.md @@ -1,169 +1,342 @@ # API Reference v2.0 -## List all Inputs. +The API is located at \/plugin/enclosure. This needs to be added before each endpoint in order for the API to function properly. The API either returns a `application/json` body or an empty body for a successful request. -Method: GET +A failed request will return an error code as well as a short error description. -http:///plugin/enclosure/inputs?apikey= +## List all inputs -Response: +Endpoint: **GET** `/inputs` + +Response (200): ``` [ { - "index_id": 1, - "label": "Input 1" + "index_id": number, + "label": string } ] ``` +Error Responses: + - none -## List a specific input. +## List a specific input -Method: GET +Endpoint: **GET** `/inputs/` -http:///plugin/enclosure/inputs/1?apikey= +*Note: id needs to be int (index_id)* -Response: +Response (200): ``` { "controlled_io": null, - "filament_sensor_timeout": 120, - "filament_sensor_enabled": true, - "temp_sensor_address": "", - "printer_action": "filament", - "controlled_io_set_value": "low", - "temp_sensor_type": "11", - "temp_sensor_navbar": true, - "temp_sensor_humidity": 19, - "edge": "fall", - "ds18b20_serial": "", - "action_type": "output_control", - "input_pull_resistor": "input_pull_up", - "input_type": "temperature_sensor", - "temp_sensor_temp": 33, - "label": "Input 1", - "index_id": 1, - "use_fahrenheit": false, - "gpio_pin": "4" + "filament_sensor_timeout": number, + "filament_sensor_enabled": boolean, + "temp_sensor_address": string, + "printer_action": string, + "controlled_io_set_value": string, + "temp_sensor_type": string, + "temp_sensor_navbar": boolean, + "temp_sensor_humidity": number, + "edge": string, + "ds18b20_serial": string, + "action_type": string, + "input_pull_resistor": string, + "input_type": string, + "temp_sensor_temp": number, + "label": string, + "index_id": number, + "use_fahrenheit": boolean, + "gpio_pin": string } ``` +Error Responses: + - 404 if specified id cannot be found + ## List all outputs -Method: GET +Endpoint: **GET** `/outputs` -http:///plugin/enclosure/outputs?apikey= - -Response: +Response (200): ``` [ { - "index_id": 1, - "label": "Ouput 1" + "index_id": number, + "label": string } ] ``` +Error Responses: + - none + ## List a specific output -Method: GET +Endpoint: **GET** `/outputs/` -http:///plugin/enclosure/outputs/1?apikey= +*Note: id needs to be int (index_id)* -Response: + +Response (200): ``` { - "linked_temp_sensor": "", - "ledstrip_gpio_dat": "", - "startup_time": 0, - "temp_ctr_deadband": 0, - "neopixel_brightness": 255, - "new_duty_cycle": "", - "gpio_pin": 0, - "default_duty_cycle": 0, - "neopixel_color": "rgb(0,0,0)", - "hide_btn_ui": false, - "temp_ctr_set_value": 0, - "temp_ctr_default_value": 0, - "default_neopixel_color": "", - "controlled_io_set_value": "Low", - "auto_shutdown": false, - "shell_script": "", - "label": "Ouput 1", - "default_ledstrip_color": "", - "duty_a": 0, - "toggle_timer_off": 0, - "alarm_set_temp": 0, - "ledstrip_gpio_clk": "", - "auto_startup": false, - "controlled_io": 0, - "shutdown_time": 0, - "temp_ctr_type": "heater", - "gcode": "M117 Test", - "shutdown_on_failed": false, - "temperature_b": 0, - "ledstrip_color": "rgb(0,0,0)", - "temperature_a": 0, - "neopixel_count": 0, - "duty_cycle": 0, - "toggle_timer_on": 0, - "show_on_navbar": false, - "duty_b": 0, - "toggle_timer": false, - "pwm_status": 50, - "gpio_status": false, - "pwm_frequency": 50, - "new_ledstrip_color": "", - "startup_with_server": true, - "active_low": true, - "temp_ctr_max_temp": 0, - "pwm_temperature_linked": false, - "temp_ctr_new_set_value": "", - "output_type": "regular", - "microcontroller_address": 0, - "index_id": 1, - "new_neopixel_color": "" + "linked_temp_sensor": string, + "ledstrip_gpio_dat": string, + "startup_time": number, + "temp_ctr_deadband": number, + "neopixel_brightness": number, + "new_duty_cycle": string, + "gpio_pin": number, + "default_duty_cycle": number, + "neopixel_color": string, + "hide_btn_ui": boolean, + "temp_ctr_set_value": number, + "temp_ctr_default_value": number, + "default_neopixel_color": string, + "controlled_io_set_value": string, + "auto_shutdown": boolean, + "shell_script": string, + "label": string, + "default_ledstrip_color": string, + "duty_a": number, + "toggle_timer_off": number, + "alarm_set_temp": number, + "ledstrip_gpio_clk": string, + "auto_startup": boolean, + "controlled_io": number, + "shutdown_time": number, + "temp_ctr_type": string, + "gcode": string, + "shutdown_on_failed": boolean, + "temperature_b": number, + "ledstrip_color": string, + "temperature_a": number, + "neopixel_count": number, + "duty_cycle": number, + "toggle_timer_on": number, + "show_on_navbar": boolean, + "duty_b": number, + "toggle_timer": boolean, + "pwm_status": number, + "gpio_status": boolean, + "pwm_frequency": number, + "new_ledstrip_color": string, + "startup_with_server": boolean, + "active_low": boolean, + "temp_ctr_max_temp": number, + "pwm_temperature_linked": boolean, + "temp_ctr_new_set_value": string, + "output_type": string, + "microcontroller_address": number, + "index_id": number, + "new_neopixel_color": string } ``` -## Enable/Disable Output: +Error Responses: + - 404 if specified id cannot be found -http:///plugin/enclosure/outputs/1?apikey= +## Control specific output -Method: PATCH -Content-Type: application/json -Body: { "status": boolean } +Endpoint: **PATCH** `/outputs/` -example: +*Note: id needs to be int (index_id)* + +Body (Content-Type: `application/json`): ``` -{ "status": true } +{ + "status": boolean +} ``` +Response (204): No-Content -## Enable/Disable Output auto-shutdown: +Error Responses: +- 400 - wrong Content-Type or malformed request +- 406 - missing information (missing attribute given in response body) -http:///plugin/enclosure/outputs/1/auto-shutdown?apikey= +## Enable/Disable Output auto-startup -Method: PATCH -Content-Type: application/json -Body: { "status": boolean } +Endpoint: **PATCH** `/outputs//auto-startup` -example: +*Note: id needs to be int (index_id)* + +Body (Content-Type: `application/json`): ``` -{ "status": true } +{ + "status": boolean +} ``` +Response (204): No-Content -## Enable/Disable Output auto-shutdown: +Error Responses: +- 400 - wrong Content-Type or malformed request +- 406 - missing information (missing attribute given in response body) -http:///plugin/enclosure/outputs/1/auto-startup?apikey= +## Control auto-shutdown for specific output -Method: PATCH -Content-Type: application/json -Body: { "status": boolean } +Endpoint: **PATCH** `/outputs//auto-shutdown` -example: +*Note: id needs to be int (index_id)* + +Body (Content-Type: `application/json`): ``` -{ "status": true } +{ + "status": boolean +} ``` + +Response (204): No-Content + +Error Responses: +- 400 - wrong Content-Type or malformed request +- 406 - missing information (missing attribute given in response body) + +## Control temperature + +Endpoint: **PATCH** `/temperature/` + +*Note: id needs to be int (index_id)* + +Body (Content-Type: `application/json`): +``` +{ + "temperature": number +} +``` + +Response (204): No-Content + +Error Responses: +- 400 - wrong Content-Type or malformed request +- 406 - missing information (missing attribute given in response body) + +## Control filament sensor + +Endpoint: **PATCH** `/filament/` + +*Note: id needs to be int (index_id)* + +Body (Content-Type: `application/json`): +``` +{ + "status": boolean +} +``` + +Response (204): No-Content + +Error Responses: +- 400 - wrong Content-Type or malformed request +- 406 - missing information (missing attribute given in response body) + +## Set PWM value + +Endpoint: **PATCH** `/pwm/` + +*Note: id needs to be int (index_id)* + +Body (Content-Type: `application/json`): +``` +{ + "duty_cycle": number +} +``` + +Response (204): No-Content + +Error Responses: +- 400 - wrong Content-Type or malformed request +- 406 - missing information (missing attribute given in response body) + +## Set RGB LED color + +Endpoint: **PATCH** `/rgb-led/` + +*Note: id needs to be int (index_id)* + +Body (Content-Type: `application/json`): +``` +{ + "rgb": string (rgb(r,g,b)) +} +``` + +Response (204): No-Content + +Error Responses: +- 400 - wrong Content-Type or malformed request +- 406 - missing information (missing attribute given in response body) + +## Set neopixel color + +Endpoint: **PATCH** `/neopixel/` + +*Note: id needs to be int (index_id)* + +Body (Content-Type: `application/json`): +``` +{ + "red": number, + "green": number, + "blue": number +} +``` + +Response (204): No-Content + +Error Responses: +- 400 - wrong Content-Type or malformed request +- 406 - missing information (missing attribute given in response body) + +## Clear GPIO Pins + +Endpoint: **POST** `/clear-gpio` + +Body: empty + +Response (204): No-Content + +Error Responses: +- none + +## Update UI + +Endpoint: **POST** `/update` + +Body: empty + +Response (204): No-Content + +Error Responses: +- none + +## Send shell command + +Endpoint: **POST** `/shell/` + +*Note: id needs to be int (index_id)* + +Body: empty + +Response (204): No-Content + +Error Responses: +- none + +## Send gcode command + +Endpoint: **POST** `/gcode/` + +*Note: id needs to be int (index_id)* + +Body: empty + +Response (204): No-Content + +Error Responses: +- none \ No newline at end of file diff --git a/octoprint_enclosure/__init__.py b/octoprint_enclosure/__init__.py index 80759b9..ebcf5b8 100644 --- a/octoprint_enclosure/__init__.py +++ b/octoprint_enclosure/__init__.py @@ -7,6 +7,7 @@ from .ledstrip import LEDStrip import octoprint.plugin import RPi.GPIO as GPIO from flask import jsonify, request, make_response, Response +from octoprint.server.util.flask import restricted_access from werkzeug.exceptions import BadRequest import time import sys @@ -152,6 +153,7 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP inputs.append(dict(index_id=index, label=label)) return Response(json.dumps(inputs), mimetype='application/json') + @octoprint.plugin.BlueprintPlugin.route("/inputs/", methods=["GET"]) def get_input_status(self, identifier): for rpi_input in self.rpi_inputs: @@ -159,7 +161,9 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP return Response(json.dumps(rpi_input), mimetype='application/json') return make_response('', 404) + @octoprint.plugin.BlueprintPlugin.route("/temperature/", methods=["PATCH"]) + @restricted_access def set_enclosure_temp_humidity(self, identifier): if "application/json" not in request.headers["Content-Type"]: return make_response("expected json", 400) @@ -179,7 +183,9 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP self.handle_temp_hum_control() return make_response('', 204) + @octoprint.plugin.BlueprintPlugin.route("/filament/", methods=["PATCH"]) + @restricted_access def set_filament_sensor(self, identifier): if "application/json" not in request.headers["Content-Type"]: return make_response("expected json", 400) @@ -200,6 +206,7 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP self._settings.set(["rpi_inputs"], self.rpi_inputs) return make_response('', 204) + @octoprint.plugin.BlueprintPlugin.route("/outputs", methods=["GET"]) def get_outputs(self): outputs = [] @@ -210,6 +217,7 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP outputs.append(dict(index_id=index, label=label)) return Response(json.dumps(outputs), mimetype='application/json') + @octoprint.plugin.BlueprintPlugin.route("/outputs/", methods=["GET"]) def get_output_status(self, identifier): for rpi_output in self.rpi_outputs: @@ -220,7 +228,9 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP return Response(json.dumps(rpi_output), mimetype='application/json') return make_response('', 404) + @octoprint.plugin.BlueprintPlugin.route("/outputs/", methods=["PATCH"]) + @restricted_access def set_io(self, identifier): if "application/json" not in request.headers["Content-Type"]: return make_response("expected json", 400) @@ -240,7 +250,9 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP self.write_gpio(self.to_int(rpi_output['gpio_pin']), val) return make_response('', 204) + @octoprint.plugin.BlueprintPlugin.route("/outputs//auto-startup", methods=["PATCH"]) + @restricted_access def set_auto_startup(self, identifier): if "application/json" not in request.headers["Content-Type"]: return make_response("expected json", 400) @@ -265,7 +277,9 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP self._settings.set(["rpi_outputs"], self.rpi_outputs) return make_response('', 204) + @octoprint.plugin.BlueprintPlugin.route("/outputs//auto-shutdown", methods=["PATCH"]) + @restricted_access def set_auto_shutdown(self, identifier): if "application/json" not in request.headers["Content-Type"]: return make_response("expected json", 400) @@ -291,25 +305,9 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP self._settings.set(["rpi_outputs"], self.rpi_outputs) return make_response('', 204) - @octoprint.plugin.BlueprintPlugin.route("/clear-gpio", methods=["POST"]) - def clear_gpio_mode(self): - GPIO.cleanup() - return make_response('', 204) - - @octoprint.plugin.BlueprintPlugin.route("/update", methods=["POST"]) - def update_ui_requested(self): - self.update_ui() - return make_response('', 204) - - @octoprint.plugin.BlueprintPlugin.route("/shell/", methods=["POST"]) - def send_shell_command(self, identifier): - rpi_output = [r_out for r_out in self.rpi_outputs if self.to_int(r_out['index_id']) == identifier].pop() - - command = rpi_output['shell_script'] - self.shell_command(command) - return make_response('', 204) @octoprint.plugin.BlueprintPlugin.route("/pwm/", methods=["PATCH"]) + @restricted_access def set_pwm(self, identifier): if "application/json" not in request.headers["Content-Type"]: return make_response("expected json", 400) @@ -318,10 +316,10 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP except BadRequest: return make_response("malformed request", 400) - if 'dutyCycle' not in data: - return make_response("missing dutyCycle attribute", 406) + if 'duty_cycle' not in data: + return make_response("missing duty_cycle attribute", 406) - set_value = self.to_int(data['dutyCycle']) + set_value = self.to_int(data['duty_cycle']) for rpi_output in [item for item in self.rpi_outputs if item['index_id'] == identifier]: rpi_output['duty_cycle'] = set_value rpi_output['new_duty_cycle'] = "" @@ -329,13 +327,30 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP self.write_pwm(gpio, set_value) return make_response('', 204) - @octoprint.plugin.BlueprintPlugin.route("/gcode/", methods=["POST"]) - def requested_gcode_command(self, identifier): - rpi_output = [r_out for r_out in self.rpi_outputs if self.to_int(r_out['index_id']) == identifier].pop() - self.send_gcode_command(rpi_output['gcode']) + @octoprint.plugin.BlueprintPlugin.route("/rgb-led/", methods=["PATCH"]) + @restricted_access + def set_ledstrip_color(self, identifier): + """ set_ledstrip_color method get request from octoprint and send the command to Open-Smart RGB LED Strip""" + if "application/json" not in request.headers["Content-Type"]: + return make_response("expected json", 400) + try: + data = request.json + except BadRequest: + return make_response("malformed request", 400) + + if 'rgb' not in data: + return make_response("missing rgb attribute", 406) + rgb = data['rgb'] + + for rpi_output in self.rpi_outputs: + if identifier == self.to_int(rpi_output['index_id']): + self.ledstrip_set_rgb(rpi_output, rgb) + return make_response('', 204) + @octoprint.plugin.BlueprintPlugin.route("/neopixel/", methods=["PATCH"]) + @restricted_access def set_neopixel(self, identifier): """ set_neopixel method get request from octoprint and send the command to arduino or neopixel""" if "application/json" not in request.headers["Content-Type"]: @@ -369,24 +384,36 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP return make_response('', 204) - @octoprint.plugin.BlueprintPlugin.route("/rgb-led/", methods=["PATCH"]) - def set_ledstrip_color(self, identifier): - """ set_ledstrip_color method get request from octoprint and send the command to Open-Smart RGB LED Strip""" - if "application/json" not in request.headers["Content-Type"]: - return make_response("expected json", 400) - try: - data = request.json - except BadRequest: - return make_response("malformed request", 400) - if 'rgb' not in data: - return make_response("missing rgb attribute", 406) - rgb = data['rgb'] + @octoprint.plugin.BlueprintPlugin.route("/clear-gpio", methods=["POST"]) + @restricted_access + def clear_gpio_mode(self): + GPIO.cleanup() + return make_response('', 204) - for rpi_output in self.rpi_outputs: - if identifier == self.to_int(rpi_output['index_id']): - self.ledstrip_set_rgb(rpi_output, rgb) + @octoprint.plugin.BlueprintPlugin.route("/update", methods=["POST"]) + @restricted_access + def update_ui_requested(self): + self.update_ui() + return make_response('', 204) + + + @octoprint.plugin.BlueprintPlugin.route("/shell/", methods=["POST"]) + @restricted_access + def send_shell_command(self, identifier): + rpi_output = [r_out for r_out in self.rpi_outputs if self.to_int(r_out['index_id']) == identifier].pop() + + command = rpi_output['shell_script'] + self.shell_command(command) + return make_response('', 204) + + + @octoprint.plugin.BlueprintPlugin.route("/gcode/", methods=["POST"]) + @restricted_access + def requested_gcode_command(self, identifier): + rpi_output = [r_out for r_out in self.rpi_outputs if self.to_int(r_out['index_id']) == identifier].pop() + self.send_gcode_command(rpi_output['gcode']) return make_response('', 204) From 046df7a51dcca706b1ea145dd7d85c40cc964a41 Mon Sep 17 00:00:00 2001 From: UnchartedBull Date: Thu, 10 Oct 2019 17:01:15 +0200 Subject: [PATCH 14/14] Fix output value not returned --- API.md | 1 + octoprint_enclosure/__init__.py | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/API.md b/API.md index e5ce300..dbee16d 100644 --- a/API.md +++ b/API.md @@ -110,6 +110,7 @@ Response (200): "shutdown_time": number, "temp_ctr_type": string, "gcode": string, + "current_value": boolean, "shutdown_on_failed": boolean, "temperature_b": number, "ledstrip_color": string, diff --git a/octoprint_enclosure/__init__.py b/octoprint_enclosure/__init__.py index ebcf5b8..129043d 100644 --- a/octoprint_enclosure/__init__.py +++ b/octoprint_enclosure/__init__.py @@ -20,6 +20,7 @@ import requests import inspect import threading import json +import copy class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplatePlugin, octoprint.plugin.SettingsPlugin, @@ -222,10 +223,10 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP def get_output_status(self, identifier): for rpi_output in self.rpi_outputs: if identifier == self.to_int(rpi_output['index_id']): - out = rpi_output.copy() + out = copy.deepcopy(rpi_output) pin = self.to_int(rpi_output['gpio_pin']) - out['val'] = GPIO.input(pin) if not rpi_output['active_low'] else (not GPIO.input(pin)) - return Response(json.dumps(rpi_output), mimetype='application/json') + out['current_value'] = GPIO.input(pin) if not rpi_output['active_low'] else (not GPIO.input(pin)) + return Response(json.dumps(out), mimetype='application/json') return make_response('', 404)