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)