sync changes #151

Merged
vitormhenrique merged 36 commits from master into dev 2018-06-15 19:52:01 +01:00
10 changed files with 296 additions and 128 deletions

21
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@@ -0,0 +1,21 @@
---
name: Bug report
about: Create a report to help us improve
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Additional context**
Add screenshots of your settings screen, so I know how to recreate the data. Also enable the debug information under the advanced section of the plugin, reproduce the issue and attach the [octoprint log](https://discourse.octoprint.org/t/where-can-i-find-octoprints-and-octopis-log-files/299) here.

View File

@@ -0,0 +1,17 @@
---
name: Feature request
about: Suggest an idea for this project
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View File

@@ -1,3 +1,12 @@
Find the plugin useful? Buy me a coffee
[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.me/VitorHenrique/2)
# Before opening an issue...
Check the [troubleshooting guide](https://github.com/vitormhenrique/OctoPrint-Enclosure/wiki/Troubleshooting-Guide). Issues with no log, no print screen *will be closed* until the necessary documentation is available.
Also, be aware that upgrading from versions lower than 4.00 will **DELETE** all settings. More information on [release notes](https://github.com/vitormhenrique/OctoPrint-Enclosure/releases/tag/4.00)
# OctoPrint-Enclosure
**Control pretty much everything that you might want to do on your raspberry pi / octoprint / enclosure**
@@ -17,11 +26,6 @@ Here is a list of possibilities:
* Notifications using IFTTT when events happen (temperature trigger / print events / etc)
* Add sub-menus on navbar to quick access outputs and temperature sensors
Find the plugin useful? Buy me a coffee
[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.me/VitorHenrique/2)
Having problems with the plugin? check the [troubleshooting guide](https://github.com/vitormhenrique/OctoPrint-Enclosure/wiki/Troubleshooting-Guide)
Check pictures on thingiverse: http://www.thingiverse.com/thing:2245493
**Software**
@@ -47,6 +51,8 @@ sudo apt-get update
sudo apt-get install build-essential python-dev python-openssl
sudo python setup.py install</code></pre>
Note: All libraries need to be installed on raspberry pi system python not octoprint virtual environment.
You can test the library by using:
<pre><code>cd examples
@@ -62,6 +68,11 @@ Start by adding the following line to /boot/config.txt
<pre><code>dtoverlay=w1-gpio</code></pre>
After rebooting, you can check if the OneWire device was found properly with
<pre><code>dmesg | grep w1-gpip</code></pre>
You should see something like
<pre><code>[ 3.030368] w1-gpio onewire@0: gpio pin 4, external pullup pin -1, parasitic power 0</code></pre>
You should be able to test your sensor by rebooting your system with sudo reboot. When the Pi is back up and you're logged in again, type the commands you see below into a terminal window. When you are in the 'devices' directory, the directory starting '28-' may have a different name, so cd to the name of whatever directory is there.
<pre><code>sudo modprobe w1-gpio
@@ -73,7 +84,7 @@ cat w1_slave</code></pre>
The response will either have YES or NO at the end of the first line. If it is yes, then the temperature will be at the end of the second line, in 1/000 degrees C.
Copy the serial number, you will need to configure the plugin
Copy the serial number, you will need to configure the plugin. Note that for the serial number includes the 28-, for example 28-0000069834ff.
* For the SI7021, BME280 and TMP102 sensors
@@ -88,9 +99,9 @@ Use the right arrow to select the button
Select yes when it asks to reboot
</code></pre>
Install some packages:
Install some packages (on raspberry pi system python not octoprint virtual environment):
<pre><code>sudo apt-get install i2c-tools python-pip</code></pre>
<pre><code>sudo apt-get install i2c-tools python-pip python-smbus</code></pre>
Find the address of the sensor:
@@ -106,11 +117,11 @@ You can use relays / mosfets to control you lights, heater, lockers etc... If yo
* Relay
The relays module that I used can be found [here](https://www.amazon.com/gp/product/B0057OC6D8?psc=1&redirect=true&ref_=oh_aui_search_detailpage). Those relays are active low, that means that they will turn on when you put LOW on the output of your pin. In order to not fry your Raspberry Pi pay attention on your wiring connection: remove the jumper link and connect 3.3v to VCC, 5V to JD-VCC and Ground to GND.
The relays module that I used couple [SainSmart 2-Channel Relay Module](https://www.amazon.com/gp/product/B0057OC6D8?ie=UTF8&tag=3dpstuff-20&camp=1789&linkCode=xm2&creativeASIN=B0057OC6D8). Those relays are active low, that means that they will turn on when you put LOW on the output of your pin. In order to not fry your Raspberry Pi pay attention on your wiring connection: remove the jumper link and connect 3.3v to VCC, 5V to JD-VCC and Ground to GND.
* Heater
For heating my enclosure I got a $15 lasko inside my enclosure. I opened it and added a relay to the mains wire. If youre uncomfortable soldering or dealing with high voltage, please check out the [PowerSwitch Tail II](http://www.powerswitchtail.com/Pages/default.aspx) . The PowerSwitch Tail II is fully enclosed, making it a lot safer.
For heating my enclosure I got a $15 lasko inside my enclosure. I opened it and added a relay to the mains wire. If youre uncomfortable soldering or dealing with high voltage, please check out the [PowerSwitch Tail II](http://www.powerswitchtail.com/) . The PowerSwitch Tail II is fully enclosed, making it a lot safer.
**CAUTION: VOLTAGE ON MAINS WIRE CAN KILL YOU, ONLY ATTEMPT TO DO THIS IF YOU KNOW WHAT YOU ARE DOING, AND DO AT YOUR OWN RISK**
@@ -118,7 +129,7 @@ For heating my enclosure I got a $15 lasko inside my enclosure. I opened it and
* Cooler
You can get a [5V small fan](https://www.amazon.com/gp/product/B003FO0LG6/ref=oh_aui_search_detailpage?ie=UTF8&psc=1) and control it over a relay.
You can get a [USB Mini Desktop Fan](https://www.amazon.com/gp/product/B00WM7TRTY?ie=UTF8&tag=3dpstuff-20&camp=1789&linkCode=xm2&creativeASIN=B00WM7TRTY) and control it over a relay.
* Filament sensor
@@ -180,8 +191,8 @@ You can do this by changing the config.yaml file as instructed on [octoprint doc
You just need to add the following section:
```
appearance:
<pre><code>appearance:
components:
order:
tab:
@@ -189,9 +200,7 @@ appearance:
- control
- gcodeviewer
- terminal
- plugin_enclosure
     - timelapse
```
- plugin_enclosure<code><pre>

View File

@@ -36,6 +36,9 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin,
temperature_sensor_data = []
last_filament_end_detected = []
print_complete = False
development_mode = False
dummy_value = 30.0
dummy_delta = 0.5
def start_timer(self):
"""
@@ -114,20 +117,26 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin,
self.configure_gpio()
self.update_ui()
self.start_outpus_with_server()
self.handle_initial_gpio_control()
self.start_timer()
self.print_complete = False
def get_settings_version(self):
return 4
return 5
def on_settings_migrate(self, target, current=None):
self._logger.warn("######### settings not compatible #########")
self._logger.warn("######### current settings version %s target settings version %s #########",
current, target)
self._settings.set(["rpi_outputs"], [])
self._settings.set(["rpi_inputs"], [])
self.rpi_outputs = self._settings.get(["rpi_outputs"])
self.rpi_inputs = self._settings.get(["rpi_inputs"])
def on_settings_migrate(self, target, current):
self._logger.warn("######### current settings version %s target settings version %s #########", current, target)
if current == 4 and target == 5:
self._logger.warn("######### migrating settings from v4 to v5 #########")
old_outputs = self._settings.get(["rpi_outputs"])
for rpi_output in old_outputs:
rpi_output['shutdown_on_failed'] = False
self._settings.set(["rpi_outputs"], old_outputs)
else:
self._logger.warn("######### settings not compatible #########")
self._settings.set(["rpi_outputs"], [])
self._settings.set(["rpi_inputs"], [])
self.rpi_inputs = self._settings.get(["rpi_inputs"])
# ~~ Blueprintplugin mixin
@octoprint.plugin.BlueprintPlugin.route("/setEnclosureTempHum", methods=["GET"])
@@ -299,7 +308,14 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin,
sudo_str = ""
cmd = sudo_str + "python " + script + str(led_pin) + " " + str(led_count) + " " + str(
led_brightness) + " " + str(red) + " " + str(green) + " " + str(blue) + " " + str(address)
led_brightness) + " " + str(red) + " " + str(green) + " " + str(blue) + " "
if neopixel_dirrect:
dma = self._settings.get(["neopixel_dma"]) or 10
cmd = cmd + str(dma)
else:
cmd = cmd + str(address)
if self._settings.get(["debug"]) is True:
if queue_id is not None:
self._logger.info("Runing scheduled queue id %s", queue_id)
@@ -321,11 +337,11 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin,
if temp is not None and hum is not None:
sensor_data.append(
dict(index_id=sensor['index_id'], temperature=temp, humidity=hum))
self.temperature_sensor_data = sensor_data
self.handle_temp_hum_control()
self.handle_temperature_events()
self.handle_pwm_linked_temperature()
self.update_ui()
self.temperature_sensor_data = sensor_data
self.handle_temp_hum_control()
self.handle_temperature_events()
self.handle_pwm_linked_temperature()
self.update_ui()
except Exception as ex:
self.log_error(ex)
@@ -425,7 +441,8 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin,
task['thread'].cancel()
self.event_queue.remove(task)
if self._settings.get(["debug"]) is True:
self._logger.info("Queue id stoped and removed from list...")
self._logger.info(
"Queue id stoped and removed from list...")
self._logger.info("Old queue list: %s", old_list)
self._logger.info("New queue list: %s", self.event_queue)
@@ -447,8 +464,10 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin,
regular_status.append(
dict(index_id=index, status=val, auto_startup=startup, auto_shutdown=shutdown))
if output['output_type'] == 'temp_hum_control':
val = GPIO.input(pin) if not output['active_low'] else (
not GPIO.input(pin))
temp_control_status.append(
dict(index_id=index, auto_startup=startup, auto_shutdown=shutdown))
dict(index_id=index, status=val, auto_startup=startup, auto_shutdown=shutdown))
if output['output_type'] == 'neopixel_indirect' or output['output_type'] == 'neopixel_direct':
val = output['neopixel_color']
neopixel_status.append(
@@ -486,27 +505,29 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin,
def get_sensor_data(self, sensor):
try:
if sensor['temp_sensor_type'] in ["11", "22", "2302"]:
self._logger.info("temp_sensor_type dht")
temp, hum = self.read_dht_temp(
sensor['temp_sensor_type'], sensor['gpio_pin'])
elif sensor['temp_sensor_type'] == "18b20":
temp = self.read_18b20_temp(sensor['ds18b20_serial'])
hum = 0
elif sensor['temp_sensor_type'] == "bme280":
temp, hum = self.read_bme280_temp(
sensor['temp_sensor_address'])
elif sensor['temp_sensor_type'] == "si7021":
temp, hum = self.read_si7021_temp(
sensor['temp_sensor_address'])
elif sensor['temp_sensor_type'] == "tmp102":
temp = self.read_tmp102_temp(
sensor['temp_sensor_address'])
hum = 0
if self.development_mode:
temp, hum = self.read_dummy_temp()
else:
self._logger.info("temp_sensor_type no match")
temp = None
hum = None
if sensor['temp_sensor_type'] in ["11", "22", "2302"]:
temp, hum = self.read_dht_temp(
sensor['temp_sensor_type'], sensor['gpio_pin'])
elif sensor['temp_sensor_type'] == "18b20":
temp = self.read_18b20_temp(sensor['ds18b20_serial'])
hum = 0
elif sensor['temp_sensor_type'] == "bme280":
temp, hum = self.read_bme280_temp(
sensor['temp_sensor_address'])
elif sensor['temp_sensor_type'] == "si7021":
temp, hum = self.read_si7021_temp(
sensor['temp_sensor_address'])
elif sensor['temp_sensor_type'] == "tmp102":
temp = self.read_tmp102_temp(
sensor['temp_sensor_address'])
hum = 0
else:
self._logger.info("temp_sensor_type no match")
temp = None
hum = None
if temp != -1 and hum != -1:
temp = round(self.to_float(
temp), 1) if not sensor['use_fahrenheit'] else round(self.to_float(temp) * 1.8 + 32, 1)
@@ -537,6 +558,17 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin,
temperature_alarm['alarm_set_temp'])
self.send_notification(msg)
def read_dummy_temp(self):
current_value = self.dummy_value
if current_value > 40 or current_value < 30:
self.dummy_delta = - self.dummy_delta
return_value = current_value + self.dummy_delta
self.dummy_value = return_value
return return_value, return_value
def read_dht_temp(self, sensor, pin):
try:
script = os.path.dirname(
@@ -554,6 +586,7 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin,
temp, hum = stdout.split("|")
return (self.to_float(temp.strip()), self.to_float(hum.strip()))
except Exception as ex:
self._logger.info("Failed to excecute python scripts, try disabling use SUDO on advanced section of the plugin.")
self.log_error(ex)
return (0, 0)
@@ -574,6 +607,7 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin,
temp, hum = stdout.split("|")
return (self.to_float(temp.strip()), self.to_float(hum.strip()))
except Exception as ex:
self._logger.info("Failed to excecute python scripts, try disabling use SUDO on advanced section of the plugin.")
self.log_error(ex)
return (0, 0)
@@ -594,6 +628,7 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin,
temp, hum = stdout.split("|")
return (self.to_float(temp.strip()), self.to_float(hum.strip()))
except Exception as ex:
self._logger.info("Failed to excecute python scripts, try disabling use SUDO on advanced section of the plugin.")
self.log_error(ex)
return (0, 0)
@@ -635,6 +670,7 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin,
self._logger.info("TMP102 result: %s", stdout)
return self.to_float(stdout.strip())
except Exception as ex:
self._logger.info("Failed to excecute python scripts, try disabling use SUDO on advanced section.")
self.log_error(ex)
return 0
@@ -708,24 +744,31 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin,
linked_data = self.get_linked_temp_sensor_data(
linked_id)
if str(temp_hum_control['temp_ctr_type']) == 'dehumidifier':
control_type = str(temp_hum_control['temp_ctr_type'])
if control_type == 'dehumidifier':
current_value = self.to_float(linked_data['humidity'])
temp_deadband = 0
else:
current_value = self.to_float(
linked_data['temperature'])
if set_temperature - temp_deadband > current_value:
current_status = True
elif set_temperature + temp_deadband < current_value:
current_status = False
if control_type == 'cooler' or control_type == 'dehumidifier':
if current_value <= set_temperature and current_value >= (set_temperature - temp_deadband):
current_status = previous_status
elif current_value < set_temperature:
current_status = False
else:
current_status = True
else:
current_status = previous_status
if current_value <= set_temperature and current_value >= (set_temperature - temp_deadband):
current_status = previous_status
elif current_value > set_temperature:
current_status = False
else:
current_status = True
if str(temp_hum_control['temp_ctr_type']) == 'cooler' or str(temp_hum_control['temp_ctr_type']) == 'dehumidifier':
current_status = not current_status
if temp_hum_control['temp_ctr_type'] == 'heater' and max_temp > 0.0 and max_temp < current_value:
if control_type == 'heater' and max_temp > 0.0 and max_temp < current_value:
if self._settings.get(["debug"]) is True:
self._logger.info(
"Maximun temperature reached for temperature control %s", temp_hum_control['index_id'])
@@ -768,7 +811,7 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin,
try:
current_mode = GPIO.getmode()
set_mode = GPIO.BOARD if self._settings.get(
["useBoardPinNumber"]) else GPIO.BCM
["use_board_pin_number"]) else GPIO.BCM
if current_mode is None:
outputs = list(filter(lambda item: item['output_type'] == 'regular' or
item['output_type'] == 'pwm' or
@@ -784,7 +827,7 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin,
elif current_mode != set_mode:
GPIO.setmode(current_mode)
tempstr = "BOARD" if current_mode == GPIO.BOARD else "BCM"
self._settings.set(["useBoardPinNumber"],
self._settings.set(["use_board_pin_number"],
True if current_mode == GPIO.BOARD else False)
warn_msg = "GPIO mode was configured before, GPIO mode will be forced to use: " + \
tempstr + " as pin numbers. Please update GPIO accordingly!"
@@ -851,16 +894,27 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin,
GPIO.setup(pin, GPIO.OUT)
pwm_instance = GPIO.PWM(pin, self.to_int(
gpio_out_pwm['pwm_frequency']))
pwm_instance.start(0)
self.pwm_intances.append({pin: pwm_instance})
for gpio_out_neopixel in list(filter(lambda item: item['output_type'] == 'neopixel_direct', self.rpi_outputs)):
pin = self.to_int(gpio_out_neopixel['gpio_pin'])
self.clear_channel(pin)
for rpi_input in list(filter(lambda item: item['input_type'] == 'gpio', self.rpi_inputs)):
pull_resistor = GPIO.PUD_UP if rpi_input['input_pull_resistor'] == 'input_pull_up' else GPIO.PUD_DOWN
gpio_pin = self.to_int(rpi_input['gpio_pin'])
pull_resistor = GPIO.PUD_UP if rpi_input['input_pull_resistor'] == 'input_pull_up' else GPIO.PUD_DOWN
GPIO.setup(gpio_pin, GPIO.IN, pull_resistor)
edge = GPIO.RISING if rpi_input['edge'] == 'rise' else GPIO.FALLING
inputs_same_gpio = list(
[r_inp for r_inp in self.rpi_inputs if self.to_int(r_inp['gpio_pin']) == gpio_pin])
if len(inputs_same_gpio) > 1:
GPIO.remove_event_detect(gpio_pin)
for other_input in inputs_same_gpio:
if other_input['edge'] is not edge:
edge = GPIO.BOTH
if rpi_input['action_type'] == 'output_control':
self._logger.info(
"Adding GPIO event detect on pin %s with edge: %s", gpio_pin, edge)
@@ -884,11 +938,14 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin,
filament_sensor['filament_sensor_enabled']):
last_detected_time = list(filter(lambda item: item['index_id'] == filament_sensor['index_id'],
self.last_filament_end_detected)).pop()['time']
if time.time() - last_detected_time > self._settings.get_int(["filament_sensor_timeout"]):
time_now = time.time()
time_difference = self.to_int(time_now - last_detected_time)
time_out_value = self.to_int(filament_sensor['filament_sensor_timeout'])
if time_difference > time_out_value:
self._logger.info("Detected end of filament.")
for item in self.last_filament_end_detected:
if item['index_id'] == filament_sensor['index_id']:
item['time'] = time.time()
item['time'] = time_now
for line in self._settings.get(["filament_sensor_gcode"]).split('\n'):
if line:
self._printer.commands(line.strip().upper())
@@ -945,39 +1002,50 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin,
self._logger.warn("Failed to stop task %s.", task)
pass
def handle_gpio_control(self, channel):
try:
if self._settings.get(["debug"]) is True:
self._logger.info(
"GPIO event triggered on channel %s", channel)
rpi_input = [r_inp for r_inp in self.rpi_inputs if self.to_int(
r_inp['gpio_pin']) == self.to_int(channel)].pop()
def handle_initial_gpio_control(self):
for rpi_input in [r_inp for r_inp in self.rpi_inputs if r_inp['action_type'] == 'output_control']:
gpio_pin = self.to_int(rpi_input['gpio_pin'])
controlled_io = self.to_int(rpi_input['controlled_io'])
if (rpi_input['edge'] == 'fall') ^ GPIO.input(gpio_pin):
rpi_output = [r_out for r_out in self.rpi_outputs if self.to_int(
r_out['index_id']) == controlled_io].pop()
if rpi_output['output_type'] == 'regular':
if rpi_input['controlled_io_set_value'] == 'toggle':
val = GPIO.LOW if GPIO.input(self.to_int(
rpi_output['gpio_pin'])) == GPIO.HIGH else GPIO.HIGH
else:
val = GPIO.LOW if rpi_input['controlled_io_set_value'] == 'low' else GPIO.HIGH
val = GPIO.LOW if rpi_input['controlled_io_set_value'] == 'low' else GPIO.HIGH
self.write_gpio(self.to_int(
rpi_output['gpio_pin']), val)
for notification in self.notifications:
if notification['gpioAction']:
msg = "GPIO control action caused by input " + str(rpi_input['label']) + ". Setting GPIO" + str(
rpi_input['controlled_io']) + " to: " + str(rpi_input['controlled_io_set_value'])
self.send_notification(msg)
if rpi_output['output_type'] == 'gcode_output':
self.send_gcode_command(rpi_output['gcode'])
for notification in self.notifications:
if notification['gpioAction']:
msg = "GPIO control action caused by input " + \
str(rpi_input['label']) + \
". Sending GCODE command"
self.send_notification(msg)
def handle_gpio_control(self, channel):
try:
if self._settings.get(["debug"]) is True:
self._logger.info(
"GPIO event triggered on channel %s", channel)
for rpi_input in [r_inp for r_inp in self.rpi_inputs if self.to_int(r_inp['gpio_pin']) == self.to_int(channel)]:
gpio_pin = self.to_int(rpi_input['gpio_pin'])
controlled_io = self.to_int(rpi_input['controlled_io'])
if (rpi_input['edge'] == 'fall') ^ GPIO.input(gpio_pin):
rpi_output = [r_out for r_out in self.rpi_outputs if self.to_int(
r_out['index_id']) == controlled_io].pop()
if rpi_output['output_type'] == 'regular':
if rpi_input['controlled_io_set_value'] == 'toggle':
val = GPIO.LOW if GPIO.input(self.to_int(
rpi_output['gpio_pin'])) == GPIO.HIGH else GPIO.HIGH
else:
val = GPIO.LOW if rpi_input['controlled_io_set_value'] == 'low' else GPIO.HIGH
self.write_gpio(self.to_int(
rpi_output['gpio_pin']), val)
for notification in self.notifications:
if notification['gpioAction']:
msg = "GPIO control action caused by input " + str(rpi_input['label']) + ". Setting GPIO" + str(
rpi_input['controlled_io']) + " to: " + str(rpi_input['controlled_io_set_value'])
self.send_notification(msg)
if rpi_output['output_type'] == 'gcode_output':
self.send_gcode_command(rpi_output['gcode'])
for notification in self.notifications:
if notification['gpioAction']:
msg = "GPIO control action caused by input " + \
str(rpi_input['label']) + \
". Sending GCODE command"
self.send_notification(msg)
except Exception as ex:
self.log_error(ex)
pass
@@ -1058,8 +1126,7 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin,
old_pwm_value = pwm['duty_cycle'] if 'duty_cycle' in pwm else -1
if not self.to_int(old_pwm_value) == self.to_int(pwm_value):
pwm['duty_cycle'] = pwm_value
pwm_object.stop()
pwm_object.start(pwm_value)
pwm_object.ChangeDutyCycle(pwm_value)
if self._settings.get(["debug"]) is True:
self._logger.info(
"Writing PWM on gpio: %s value %s", gpio, pwm_value)
@@ -1128,6 +1195,7 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin,
if event == Events.PRINT_STARTED:
self.print_complete = False
self.cancel_all_events_on_queue()
self.event_queue = []
self.start_filament_detection()
for rpi_output in self.rpi_outputs:
if rpi_output['auto_startup']:
@@ -1165,6 +1233,19 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin,
elif event in (Events.PRINT_CANCELLED, Events.PRINT_FAILED):
self.stop_filament_detection()
self.cancel_all_events_on_queue()
self.event_queue = []
for rpi_output in self.rpi_outputs:
if rpi_output['shutdown_on_failed']:
shutdown_time = rpi_output['shutdown_time']
if rpi_output['output_type'] == 'pwm' and rpi_output['pwm_temperature_linked']:
rpi_output['duty_cycle'] = rpi_output['default_duty_cycle']
if rpi_output['auto_shutdown'] and not self.is_hour(shutdown_time):
delay_seconds = self.to_float(shutdown_time)
self.schedule_auto_shutdown_outputs(
rpi_output, delay_seconds)
if rpi_output['output_type'] == 'temp_hum_control':
rpi_output['temp_ctr_set_value'] = 0
self.run_tasks()
if event == Events.PRINT_DONE:
for notification in self.notifications:
@@ -1194,7 +1275,7 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin,
shutdown_delay_seconds, rpi_output, value, sufix)
if rpi_output['output_type'] == 'pwm' and rpi_output['pwm_temperature_linked']:
self.schedule_pwm_duty_on_queue(
shutdown_delay_seconds, rpi_output, 0)
shutdown_delay_seconds, rpi_output, 0, sufix)
if (rpi_output['output_type'] == 'neopixel_indirect' or rpi_output['output_type'] == 'neopixel_direct'):
self.add_neopixel_output_to_queue(
rpi_output, shutdown_delay_seconds, 0, 0, 0, sufix)
@@ -1296,9 +1377,9 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin,
self.event_queue.append(dict(queue_id=queue_id, thread=thread))
def schedule_pwm_duty_on_queue(self, delay_seconds, rpi_output, value):
queue_id = '{0!s}_{1!s}'.format(
rpi_output['index_id'], "pwm_linked_temp")
def schedule_pwm_duty_on_queue(self, delay_seconds, rpi_output, value, sufix):
queue_id = '{0!s}_{1!s}_{2!s}'.format(
rpi_output['index_id'], "pwm_linked_temp", sufix)
thread = threading.Timer(delay_seconds,
self.set_pwm_duty_cycle,
args=[rpi_output, value, queue_id])
@@ -1381,10 +1462,11 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin,
"M82 ;Set extruder to Absolute Mode\n" +
"G92 E0 ;Set Extruder to 0",
use_sudo=True,
neopixel_dma=10,
debug=False,
gcode_control=False,
debug_temperature_log=False,
useBoardPinNumber=False,
use_board_pin_number=False,
notification_provider="disabled",
notification_api_key="",
notification_event_name="printer_event",

View File

@@ -3,7 +3,6 @@ import sys
import time
LED_INVERT = False
LED_DMA = 5
LED_FREQ_HZ = 800000
if len(sys.argv) == 8:
@@ -13,7 +12,7 @@ if len(sys.argv) == 8:
red = int(sys.argv[4])
green = int(sys.argv[5])
blue = int(sys.argv[6])
address = int(sys.argv[7], 16)
LED_DMA = int(sys.argv[7], 16)
else:
print("fail")
sys.exit(1)

View File

@@ -43,13 +43,17 @@ $(function () {
});
});
self.use_sudo = ko.observable();
self.gcode_control = ko.observable();
self.neopixel_dma = ko.observable();
self.debug = ko.observable();
self.debug_temperature_log = ko.observable();
self.use_board_pin_number = ko.observable();
self.filament_sensor_gcode = ko.observable();
self.notification_provider = ko.observable();
self.notification_event_name = ko.observable();
self.notification_api_key = ko.observable();
self.notifications = ko.observable();
self.notifications = ko.observableArray([]);
self.humidityCapableSensor = function(sensor){
if (['11', '22', '2302', 'bme280', 'si7021'].indexOf(sensor) >= 0){
@@ -83,6 +87,11 @@ $(function () {
});
};
self.calculateRowSpan = function(index_id){
span = self.linkedTemperatureControl(index_id())().length
return span == 0 ? 1 : span;
};
self.hasAnySensorWithHumidity = function(){
return_value = false;
self.rpi_inputs_temperature_sensors().forEach(function (sensor) {
@@ -183,6 +192,7 @@ $(function () {
return (output['index_id'] == item.index_id());
}).pop();
if (linked_output) {
linked_output.gpio_status(output['status'])
linked_output.auto_shutdown(output['auto_shutdown'])
linked_output.auto_startup(output['auto_startup'])
}
@@ -256,24 +266,28 @@ $(function () {
return duty_cycle;
}
self.bindSettings = function(){
self.bindFromSettings = function(){
self.rpi_outputs(self.settingsViewModel.settings.plugins.enclosure.rpi_outputs());
self.rpi_inputs(self.settingsViewModel.settings.plugins.enclosure.rpi_inputs());
self.debug(self.settingsViewModel.settings.plugins.enclosure.debug())
self.debug_temperature_log(self.settingsViewModel.settings.plugins.enclosure.debug_temperature_log())
self.filament_sensor_gcode(self.settingsViewModel.settings.plugins.enclosure.filament_sensor_gcode())
self.notification_provider(self.settingsViewModel.settings.plugins.enclosure.notification_provider())
self.notification_event_name(self.settingsViewModel.settings.plugins.enclosure.notification_event_name())
self.notification_api_key(self.settingsViewModel.settings.plugins.enclosure.notification_api_key())
self.notifications(self.settingsViewModel.settings.plugins.enclosure.notifications())
self.use_sudo(self.settingsViewModel.settings.plugins.enclosure.use_sudo());
self.gcode_control(self.settingsViewModel.settings.plugins.enclosure.gcode_control());
self.neopixel_dma(self.settingsViewModel.settings.plugins.enclosure.neopixel_dma());
self.debug(self.settingsViewModel.settings.plugins.enclosure.debug());
self.debug_temperature_log(self.settingsViewModel.settings.plugins.enclosure.debug_temperature_log());
self.use_board_pin_number(self.settingsViewModel.settings.plugins.enclosure.use_board_pin_number());
self.filament_sensor_gcode(self.settingsViewModel.settings.plugins.enclosure.filament_sensor_gcode());
self.notification_provider(self.settingsViewModel.settings.plugins.enclosure.notification_provider());
self.notification_event_name(self.settingsViewModel.settings.plugins.enclosure.notification_event_name());
self.notification_api_key(self.settingsViewModel.settings.plugins.enclosure.notification_api_key());
self.notifications(self.settingsViewModel.settings.plugins.enclosure.notifications());
};
self.onBeforeBinding = function () {
self.bindSettings();
self.bindFromSettings();
};
self.onSettingsBeforeSave = function() {
self.bindSettings();
self.bindFromSettings();
};
self.onStartupComplete = function () {
@@ -362,6 +376,7 @@ $(function () {
controlled_io_set_value: ko.observable("Low"),
startup_time: ko.observable(0),
auto_shutdown: ko.observable(false),
shutdown_on_failed: ko.observable(false),
shutdown_time: ko.observable(0),
linked_temp_sensor: ko.observable(""),
alarm_set_temp: ko.observable(0),

View File

@@ -204,6 +204,15 @@
</div>
<!-- /ko -->
<!-- ko if: $data.auto_shutdown -->
<div class="control-group">
<div class="controls">
<label class="checkbox">
<input type="checkbox" data-bind="checked: shutdown_on_failed"> {{ _('Shutdown on Failed or Canceled') }}
</label>
<span class="help-inline">Choose if output should turn off automatomatically when print is canceled or fails</span>
</div>
</div>
<div data-bind="attr: {id: 'auto_shutdownField_' + $index() }">
<div class="control-group">
<label class="control-label">{{ _('Shutdown Delay / Hour') }}</label>
@@ -294,13 +303,16 @@
</div>
</div>
<!-- ko if: $data.auto_startup || $data.startup_with_server -->
<div class="control-group">
<label class="control-label">{{ _('Default Value') }}</label>
<div class="controls">
<input type="text" class="input-block-level" data-bind="value: temp_ctr_default_value">
<span class="help-inline">Default temperature / humidity that temperature control will be set when the print starts.</span>
<span class="help-inline">Default temperature / humidity that temperature control will be set when the print starts or the server starts.</span>
</div>
</div>
<!-- /ko -->
<div class="control-group">
<label class="control-label">{{ _('Value Deadband') }}</label>
<div class="controls">
@@ -500,7 +512,7 @@
<div class="controls">
<input type="text" class="input-block-level" data-bind="value: ds18b20_serial" value="">
<span class="help-inline">DS18B20 serial value, needs to be used to have support for multiple sensors, read documentation on github page
for more information</span>
for more information. The serial is typically in the form of 28-0123456789ab.</span>
</div>
</div>
<!-- /ko -->
@@ -714,6 +726,13 @@
<a href=" https://github.com/vitormhenrique/OctoPrint-Enclosure">github</a> page</span>
</div>
</div>
<div class="control-group">
<label class="control-label">{{ _('Neopixel DMA Channel') }}</label>
<div class="controls">
<input type="text" class="input-block-level" data-bind="value: settingsViewModel.settings.plugins.enclosure.neopixel_dma">
<span class="help-inline">DMA channel used on direct control of neopixel.</span>
</div>
</div>
<div class="control-group">
<div class="controls">
<label class="checkbox">
@@ -722,7 +741,7 @@
<span class="help-inline">Log additional information on octoprint log to help trouble shoot the plugin</span>
</div>
</div>
<!-- ko if: ($root.settingsViewModel.settings.plugins.enclosure.debug()) -->
<!-- ko if: ($root.debug()) -->
<div class="control-group">
<div class="controls">
<label class="checkbox">
@@ -735,7 +754,7 @@
<div class="control-group">
<div class="controls">
<label class="checkbox">
<input type="checkbox" data-bind="checked: settingsViewModel.settings.plugins.enclosure.useBoardPinNumber"> {{ _('Use Board Pin #') }}
<input type="checkbox" data-bind="checked: settingsViewModel.settings.plugins.enclosure.use_board_pin_number"> {{ _('Use Board Pin #') }}
</label>
<span class="help-inline">Use BOARD pin numbers instead of BCM pin numbers</span>
</div>
@@ -749,7 +768,7 @@
</div>
<div class="control-group">
<label class="control-label" for="settings-enclosure-filament-sensor">{{ _('Filament Change Gcode') }}</label>
<label class="control-label">{{ _('Filament Change Gcode') }}</label>
<div class="controls">
<textarea rows="4" class="block" data-bind="value: settingsViewModel.settings.plugins.enclosure.filament_sensor_gcode"></textarea>
<span class="help-inline">GCODE that will be sent to the printer to pause and allow filament to be changed. You should add
@@ -770,17 +789,17 @@
<div class="control-group">
<label class="control-label">{{ _('Event Name') }}</label>
<div class="controls">
<input type="text" class="input-block-level" data-bind="value: settingsViewModel.settings.plugins.enclosure.notification_event_name">
<input type="text" class="input-block-level" data-bind="value: notification_event_name">
<span class="help-inline">Event name that was configured on the maker chanel of IFTTT, don't use space between the words</span>
</div>
</div>
<div class="control-group">
<label class="control-label">{{ _('IFTTT API KEY') }}</label>
<div class="controls">
<input type="text" class="input-block-level" data-bind="value:settingsViewModel.settings.plugins.enclosure.notification_api_key">
<input type="text" class="input-block-level" data-bind="value: notification_api_key">
</div>
</div>
<div class="control-group" data-bind="foreach: settingsViewModel.settings.plugins.enclosure.notifications">
<div class="control-group" data-bind="foreach: notifications">
<div class="controls">
<label class="checkbox">
<input type="checkbox" data-bind="checked: temperatureAction"> {{ _('Notify temperature actions') }}

View File

@@ -20,8 +20,8 @@
<!-- ko foreach: $root.rpi_inputs_temperature_sensors() -->
<tr>
<th class="temperature_sensor" data-bind="text: label, attr: {title: label, rowspan: $root.linkedTemperatureControl(index_id())().length}"></th>
<td class="temperature_actual" data-bind="attr: {rowspan: $root.linkedTemperatureControl(index_id())().length}">
<th class="temperature_sensor" data-bind="text: label, attr: {title: label, rowspan: $root.calculateRowSpan(index_id)}"></th>
<td class="temperature_actual" data-bind="attr: {rowspan: $root.calculateRowSpan(index_id)}">
<span data-bind="text: temp_sensor_temp, attr: {title: temp_sensor_temp}"> </span>
<!-- ko if: (use_fahrenheit()) -->
<span class="add-on">&deg;F</span>
@@ -31,7 +31,7 @@
<!-- /ko -->
</td>
<!-- ko if: ($root.humidityCapableSensor(temp_sensor_type())) -->
<td class="humidity_actual" data-bind="attr: {rowspan: $root.linkedTemperatureControl(index_id())().length}">
<td class="humidity_actual" data-bind="attr: {rowspan: $root.calculateRowSpan(index_id)}">
<span data-bind="text: temp_sensor_humidity, attr: {title: temp_sensor_humidity}"> </span>
<span class="add-on">%</span>
</td>
@@ -39,7 +39,7 @@
<!-- ko if: ($root.hasAnySensorWithHumidity()) -->
<!-- ko ifnot: ($root.humidityCapableSensor(temp_sensor_type())) -->
<td class="humidity_actual" data-bind="attr: {rowspan: $root.linkedTemperatureControl(index_id())().length}">N/A</td>
<td class="humidity_actual" data-bind="attr: {rowspan: $root.calculateRowSpan(index_id)}">N/A</td>
<!-- /ko -->
<!-- /ko -->
@@ -216,6 +216,12 @@
<!-- ko if: ($data.temp_ctr_type() == "dehumidifier") -->
<span class="badge badge-warning">Dehumidifier</span>
<!-- /ko -->
<!-- ko if: ($data.gpio_status()) -->
<span class="badge badge-success help-inline">on</span>
<!-- /ko -->
<!-- ko ifnot: ($data.gpio_status()) -->
<span class="badge badge-important help-inline">off</span>
<!-- /ko -->
</h4>
<!-- /ko -->
@@ -286,4 +292,4 @@
<!-- /ko -->
</h4>
<!-- /ko -->
<!-- /ko -->
<!-- /ko -->

View File

@@ -42,7 +42,7 @@ def main():
# Divide by 16 to get value in celsius
temp /= 16.0
print temp
print('{0:0.1f}'.format(temp))
if __name__ == "__main__":
main()

View File

@@ -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 = "3.51"
plugin_version = "4.09"
# The plugin's description. Can be overwritten within OctoPrint's internal data via __plugin_description__ in the plugin
# module