Added full support for Adafruit DotStar LED Strips.

This commit is contained in:
IvanGirderboot
2021-02-09 19:38:11 -07:00
parent db22b12d83
commit d41fcfc1e7
5 changed files with 323 additions and 4 deletions

View File

@@ -141,8 +141,8 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP
self.generate_temp_hum_control_status()
self.setup_gpio()
self.configure_gpio()
self.update_ui()
self.start_outpus_with_server()
self.update_ui()
self.handle_initial_gpio_control()
self.start_timer()
self.print_complete = False
@@ -628,6 +628,48 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP
return jsonify(success=True)
@octoprint.plugin.BlueprintPlugin.route("/setDotstar", methods=["GET"])
def set_dotstar_old(self):
""" set_dotstar method get request from octoprint and send the command to dotstar"""
gpio_index = self.to_int(request.values["index_id"])
action = request.values["action"]
for rpi_output in self.rpi_outputs:
if gpio_index == self.to_int(rpi_output['index_id']):
#self._logger.info("DotStar Output Data: %s", rpi_output)
led_count = rpi_output['dotstar_count']
use_spi = rpi_output['dotstar_use_spi']
if use_spi == True:
data_pin = 0
clock_pin = 0
else:
data_pin =self.to_int(rpi_output['dotstar_data_pin'])
clock_pin = self.to_int(rpi_output['dotstar_clock_pin'])
if action == "setColor" :
active = True
red = request.values["red"]
green = request.values["green"]
blue = request.values["blue"]
led_brightness = request.values["brightness"]
elif action == "setPower":
led_brightness = rpi_output['dotstar_brightness']
#self._logger.info("DotStar Requested Power: %s", request.values["status"])
if request.values["status"] == "true":
active = True
else:
active = False
if rpi_output['dotstar_color'] is None:
red, green, blue = self.get_color_from_rgb(rpi_output['default_dotstar_color'])
else:
red, green, blue = self.get_color_from_rgb(rpi_output['dotstar_color'])
self.send_dotstar_command(gpio_index, active, data_pin, clock_pin, led_count, led_brightness, red, green, blue)
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"""
@@ -642,8 +684,43 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP
# DEPREACTION END
def send_dotstar_command(self, index_id, active, data_pin, clock_pin, led_count, led_brightness, red, green, blue, queue_id=None):
if queue_id is not None:
self._logger.debug("running scheduled queue id %s", queue_id)
self.stop_queue_item(queue_id)
# Import here so we don't rely on this library when no dotstar strip is in use.
try:
import board
import adafruit_dotstar as dotstar
self._logger.info("DotStar Modules Imported")
# Assume SPI if clock or data pin is 0
if ((self.to_int(data_pin) == 0) or (self.to_int(clock_pin) == 0)):
clock_pin = board.SCK
data_pin = board.MOSI
dots = dotstar.DotStar(clock_pin, data_pin, self.to_int(led_count), brightness=self.to_float(led_brightness))
if active:
self._logger.info("Setting DotStar color and brightness")
dots.fill((self.to_int(red),self.to_int(green),self.to_int(blue)))
# Update color, brightness, and power with current values sent to the strip
for rpi_output in self.rpi_outputs:
if self.to_int(index_id) == self.to_int(rpi_output['index_id']):
rpi_output['dotstar_color'] = 'rgb({0!s},{1!s},{2!s})'.format(red, green, blue)
rpi_output['dotstar_brightness'] = led_brightness
rpi_output['dotstar_active'] = True
else:
self._logger.info("Turning off DotStar")
dots.fill(0)
for rpi_output in self.rpi_outputs:
if self.to_int(index_id) == self.to_int(rpi_output['index_id']):
rpi_output['dotstar_active'] = False
self.update_ui_outputs()
except Exception as ex:
self._logger.warn(ex)
def send_neopixel_command(self, led_pin, led_count, led_brightness, red, green, blue, address, neopixel_dirrect,
index_id, queue_id=None):
@@ -802,6 +879,7 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP
regular_status = []
pwm_status = []
neopixel_status = []
dotstar_status = []
temp_control_status = []
for output in self.rpi_outputs:
index = self.to_int(output['index_id'])
@@ -821,6 +899,12 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP
val = output['neopixel_color']
neopixel_status.append(
dict(index_id=index, color=val, auto_startup=startup, auto_shutdown=shutdown))
if output['output_type'] == 'dotstar':
col = output['dotstar_color']
level = output['dotstar_brightness']
pwr = output['dotstar_active']
dotstar_status.append(
dict(index_id=index, color=col, brightness=level, active=pwr, auto_startup=startup, auto_shutdown=shutdown))
if output['output_type'] == 'pwm':
for pwm in self.pwm_instances:
if pin in pwm:
@@ -834,6 +918,7 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP
self._plugin_manager.send_plugin_message(self._identifier,
dict(rpi_output_regular=regular_status, rpi_output_pwm=pwm_status,
rpi_output_neopixel=neopixel_status,
rpi_output_dotstar=dotstar_status,
rpi_output_temp_hum_ctrl=temp_control_status))
except Exception as ex:
self.log_error(ex)
@@ -1661,6 +1746,9 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP
self.schedule_pwm_duty_on_queue(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)
if (rpi_output['output_type'] == 'dotstar'):
active = False
self.add_dotstar_output_to_queue(rpi_output, shutdown_delay_seconds, active, 0, 0, 0, 0, sufix)
if rpi_output['output_type'] == 'temp_hum_control':
value = 0
self.add_temperature_output_temperature_queue(shutdown_delay_seconds, rpi_output, value, sufix)
@@ -1700,6 +1788,20 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP
neopixel_direct = 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_direct, index_id)
if (rpi_output['output_type'] == 'dotstar'):
index_id = self.to_int(rpi_output['index_id'])
red, green, blue = self.get_color_from_rgb(rpi_output['default_dotstar_color'])
brightness = rpi_output['default_dotstar_brightness']
led_count = rpi_output['dotstar_count']
use_spi = rpi_output['dotstar_use_spi']
if use_spi == True:
data_pin = 0
clock_pin = 0
else:
data_pin =self.to_int(rpi_output['dotstar_data_pin'])
clock_pin = self.to_int(rpi_output['dotstar_clock_pin'])
active = True
self.send_dotstar_command(index_id, active, data_pin, clock_pin, led_count, brightness, red, green, blue)
if rpi_output['output_type'] == 'temp_hum_control':
rpi_output['temp_ctr_set_value'] = rpi_output['temp_ctr_default_value']
@@ -1716,6 +1818,11 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP
if (rpi_output['output_type'] == 'neopixel_indirect' or rpi_output['output_type'] == 'neopixel_direct'):
red, green, blue = self.get_color_from_rgb(rpi_output['default_neopixel_color'])
self.add_neopixel_output_to_queue(rpi_output, delay_seconds, red, green, blue, sufix)
if (rpi_output['output_type'] == 'dotstar'):
red, green, blue = self.get_color_from_rgb(rpi_output['default_dotstar_color'])
brightness = rpi_output['default_dotstar_brightness']
active = True
self.add_dotstar_output_to_queue(rpi_output, delay_seconds, active, red, green, blue, brightness, sufix)
if rpi_output['output_type'] == 'temp_hum_control':
value = rpi_output['temp_ctr_default_value']
self.add_temperature_output_temperature_queue(delay_seconds, rpi_output, value, sufix)
@@ -1760,6 +1867,26 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP
self.event_queue.append(dict(queue_id=queue_id, thread=thread))
def add_dotstar_output_to_queue(self, rpi_output, delay_seconds, active, red, green, blue, brightness, sufix):
led_count = rpi_output['dotstar_count']
use_spi = rpi_output['dotstar_use_spi']
if use_spi == True:
data_pin = 0
clock_pin = 0
else:
data_pin =self.to_int(rpi_output['dotstar_data_pin'])
clock_pin = self.to_int(rpi_output['dotstar_clock_pin'])
index_id = self.to_int(rpi_output['index_id'])
queue_id = '{0!s}_{1!s}'.format(index_id, sufix)
self._logger.debug("Scheduling dotstar output id %s for on %s delay_seconds", queue_id, delay_seconds)
thread = threading.Timer(delay_seconds, self.send_dotstar_command,
args=[index_id, active, data_pin, clock_pin, led_count, brightness, red, green, blue, queue_id])
# (self, index_id, active, data_pin, clock_pin, led_count, led_brightness, red, green, blue
self.event_queue.append(dict(queue_id=queue_id, thread=thread))
def add_pwm_output_to_queue(self, delay_seconds, rpi_output, value, sufix):
queue_id = '{0!s}_{1!s}'.format(rpi_output['index_id'], sufix)

View File

@@ -106,7 +106,7 @@ $(function () {
self.hasAnyNavbarOutput = function(){
return_value = false;
self.rpi_outputs().forEach(function (output) {
if ((output.output_type()=="regular" || output.output_type()=="gcode_output") && output.show_on_navbar()) {
if ((output.output_type()=="regular" || output.output_type()=="gcode_output" || output.output_type()=="dotstar" ) && output.show_on_navbar()) {
return_value = true;
return false;
}
@@ -225,6 +225,21 @@ $(function () {
})
}
if (data.hasOwnProperty("rpi_output_dotstar")) {
data.rpi_output_dotstar.forEach(function (output) {
var linked_output = ko.utils.arrayFilter(self.rpi_outputs(), function (item) {
return (output['index_id'] == item.index_id());
}).pop();
if (linked_output) {
linked_output.dotstar_color(output['color'])
linked_output.dotstar_active(output['active'])
linked_output.dotstar_brightness(output['brightness'])
linked_output.auto_shutdown(output['auto_shutdown'])
linked_output.auto_startup(output['auto_startup'])
}
})
}
if (data.hasOwnProperty("rpi_output_ledstrip")) {
data.rpi_output_ledstrip.forEach(function (output) {
var linked_output = ko.utils.arrayFilter(self.rpi_outputs(), function (item) {
@@ -414,6 +429,18 @@ $(function () {
new_neopixel_color: ko.observable(""),
neopixel_count: ko.observable(0),
neopixel_brightness: ko.observable(255),
dotstar_color: ko.observable("rgb(0,0,0)"),
default_dotstar_color: ko.observable(""),
new_dotstar_color: ko.observable(""),
new_dotstar_brightness: ko.observable(""),
dotstar_count: ko.observable(0),
dotstar_brightness: ko.observable(1),
default_dotstar_brightness: ko.observable(""),
dotstar_use_spi: ko.observable(true),
dotstar_gpio_clk: ko.observable(""),
dotstar_gpio_dat: ko.observable(""),
dotstar_brightness: ko.observable(""),
dotstar_active: ko.observable(false),
ledstrip_color: ko.observable("rgb(0,0,0)"),
default_ledstrip_color: ko.observable(""),
new_ledstrip_color: ko.observable(""),
@@ -657,6 +684,73 @@ $(function () {
}
};
self.handleDotstarColor = function (item) {
self.handleDotstar(item, item.new_dotstar_color(), item.dotstar_brightness())
}
self.handleDotstarBrightness = function (item) {
self.handleDotstar(item, item.dotstar_color(), item.new_dotstar_brightness())
}
self.handleDotstar = function (item, color, brightness) {
var index = item.index_id() ;
//var or_tempStr = item.new_dotstar_color();
var tempStr = color.replace("rgb(", "");
var r = parseInt(tempStr.substring(0, tempStr.indexOf(",")));
tempStr = tempStr.slice(tempStr.indexOf(",") + 1);
var g = parseInt(tempStr.substring(0, tempStr.indexOf(",")));
tempStr = tempStr.slice(tempStr.indexOf(",") + 1);
var b = parseInt(tempStr.substring(0, tempStr.indexOf(")")));
if (r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255 || isNaN(r) || isNaN(g) || isNaN(b)) {
new PNotify({
title: "Enclosure",
text: "Color needs to follow the format rgb(value_red,value_green,value_blue)!",
type: "error"
});
} else {
$.ajax({
type: "GET",
dataType: "json",
data: {
"index_id": index,
"action": "setColor",
"red": r,
"green": g,
"blue": b,
"brightness": brightness
},
url: self.buildPluginUrl("/setDotstar"),
success: function (data) {
item.new_dotstar_color("");
self.getUpdateUI();
}
});
}
};
self.handleDotstarPower = function (item, form) {
var request = {
"status": !item.dotstar_active(),
"index_id": item.index_id(),
"action": "setPower"
};
$.ajax({
type: "GET",
dataType: "json",
data: request,
url: self.buildPluginUrl("/setDotstar"),
success: function (data) {
self.getUpdateUI();
}
});
};
self.handleLedstripColor = function (item) {
var index = item.index_id() ;
var or_tempStr = item.new_ledstrip_color();

View File

@@ -20,6 +20,20 @@
</li>
<!-- /ko -->
<!-- ko if: ($data.output_type() == "dotstar") -->
<li>
<a href="javascript:void(0)" data-bind="click: $root.handleDotstarPower">
<span data-bind="html: label"> </span>
<!-- ko if: ($data.dotstar_active()) -->
<span class="badge badge-success help-inline">on</span>
<!-- /ko -->
<!-- ko ifnot: ($data.dotstar_active()) -->
<span class="badge badge-important help-inline">off</span>
<!-- /ko -->
</a>
</li>
<!-- /ko -->
<!-- ko if: ($data.output_type() == "gcode_output") -->
<!-- ko if: ($root.isOperational()) -->
<li>

View File

@@ -35,6 +35,12 @@
</span>
</label>
</div>
<div class="controls">
<label class="radio">
<input type="radio" value="dotstar" data-bind="checked: output_type, attr: {name: 'output_type_' + $index() }"> {{ _('DotStar RGB Strip') }}
</span>
</label>
</div>
<div class="controls">
<label class="radio">
<input type="radio" value="ledstrip" data-bind="checked: output_type, attr: {name: 'output_type_' + $index() }"> {{ _('RGB LED Strip') }}
@@ -91,7 +97,7 @@
</div>
</div>
<!-- /ko -->
<!-- ko ifnot: ($data.output_type() == "gcode_output" || $data.output_type() == "temperature_alarm" || $data.output_type() == "shell_output" || $data.output_type() == "ledstrip") -->
<!-- ko ifnot: ($data.output_type() == "gcode_output" || $data.output_type() == "temperature_alarm" || $data.output_type() == "shell_output" || $data.output_type() == "ledstrip" || $data.output_type() == "dotstar" ) -->
<div class="control-group">
<label class="control-label">{{ _('IO Number') }}</label>
<div class="controls">
@@ -263,7 +269,7 @@
</div>
<!-- /ko -->
<!-- ko if: ($data.output_type() == "regular" || $data.output_type() == "gcode_output" || $data.output_type() == "shell_output" || $data.output_type() == "ledstrip") -->
<!-- ko if: ($data.output_type() == "regular" || $data.output_type() == "gcode_output" || $data.output_type() == "shell_output" || $data.output_type() == "ledstrip" || $data.output_type() == "dotstar") -->
<div class="control-group">
<div class="controls">
<label class="checkbox">
@@ -411,6 +417,49 @@
<code>i2cdetect -y 1</code> on your Raspberry Pi</span>
</div>
</div>
<!-- /ko -->
<!-- ko if: ($data.output_type() == "dotstar") -->
<div class="controls">
<label class="checkbox">
<input type="checkbox" data-bind="checked: dotstar_use_spi"> {{ _('Use SPI') }}
</label>
<span class="help-inline">Use SPI Interface Directly (Ignores Data/Clock Pin settings)<br/>
Connect the Dotstar to the MOSI and MCLK pins on the Raspberry Pi</span>
</div>
<div class="control-group">
<label class="control-label">{{ _('CLK') }}</label>
<div class="controls">
<input type="text" class="input-block-level" data-bind="value: dotstar_gpio_clk">
<span class="help-inline">Choose any GPIO pin to provide the Clock signal</span>
</div>
<label class="control-label">{{ _('DAT') }}</label>
<div class="controls">
<input type="text" class="input-block-level" data-bind="value: dotstar_gpio_dat">
<span class="help-inline">Choose any GPIO pin to provide the Data</span>
</div>
</div>
<div class="control-group">
<label class="control-label">{{ _('Number of LEDS') }}</label>
<div class="controls">
<input type="text" class="input-block-level" data-bind="value: dotstar_count">
<span class="help-inline">Number of led's on strip</span>
</div>
</div>
<div class="control-group">
<label class="control-label">{{ _('Default Brightness') }}</label>
<div class="controls">
<input type="text" class="input-block-level" data-bind="value: default_dotstar_brightness">
<span class="help-inline">Value between 0 and 1</span>
</div>
</div>
<div class="control-group">
<label class="control-label">{{ _('Default Color') }}</label>
<div class="controls">
<input type="text" class="input-block-level" data-bind="value: default_dotstar_color, attr: {name: 'colorpicker' } , click: $root.showColorPicker()">
<span class="help-inline">Value needs to follow the format rgb(value_red,value_green,value_blue) where values should be between 0 and 255</span>
</div>
</div>
<!-- /ko -->
<!-- ko if: ($data.output_type() == "ledstrip") -->
<div class="control-group">

View File

@@ -226,6 +226,41 @@
</div>
<!-- /ko -->
<!-- ko if: ($data.output_type() == "dotstar") -->
<h4>
<span data-bind="html: label"> </span>
<span class="badge">DotStar</span>
<!-- ko if: ($data.dotstar_active()) -->
<span class="badge badge-success help-inline">on</span>
<!-- /ko -->
<!-- ko ifnot: ($data.dotstar_active()) -->
<span class="badge badge-important help-inline">off</span>
<!-- /ko -->
</h4>
<div>
<!-- ko if: ($data.dotstar_active()) -->
<button data-bind="enable: $root.isUser(), click: $root.handleDotstarPower" class="btn">Turn off</button>
<!-- /ko -->
<!-- ko ifnot: ($data.dotstar_active()) -->
<button data-bind="enable: $root.isUser(), click: $root.handleDotstarPower" class="btn">Turn on</button>
<!-- /ko -->
</div>
<div class="input-append dotstar-div">
Color: <input type="text" class="input-block-level" data-bind="click: $root.showColorPicker(), value: new_dotstar_color, valueUpdate: 'input', attr: {placeholder:dotstar_color, name: 'colorpicker'}">
<button type="submit" class="btn btn-input-inc" title="Set Color" data-bind="enable: $root.isUser(), click: $root.handleDotstarColor">
<i class="fa fa-check"></i>
</button>
</div>
<div class="input-append dotstar-div">
Brightness: <input type="text" class="input-block-level" data-bind="value: new_dotstar_brightness, valueUpdate: 'input', attr: {placeholder:dotstar_brightness, name: 'brightness'}">
<button type="submit" class="btn btn-input-inc" title="Set Brightness" data-bind="enable: $root.isUser(), click: $root.handleDotstarBrightness">
<i class="fa fa-check"></i>
</button>
</div>
<!-- /ko -->
<!-- ko if: ($data.output_type() == "temp_hum_control") -->
<h4>
<span data-bind="html: label"> </span>