Added support for adafruit EMC2101 #480

Merged
JeremyLaurenson merged 3 commits from master into master 2025-05-01 17:15:39 +01:00
4 changed files with 180 additions and 8 deletions

View File

@@ -0,0 +1,26 @@
import time
import board
from adafruit_emc2101.emc2101_lut import EMC2101_LUT as EMC2101
i2c = board.I2C() # uses board.SCL and board.SDA
FAN_MAX_RPM = 1700
emc = EMC2101(i2c)
def getTemp():
return(emc.internal_temperature)
def getSpeed():
return(emc.fan_speed)
def main():
try:
temperature = getTemp()
fanspeed = getSpeed()
print('{0:0.1f} | {1:0.1f}'.format(temperature, fanspeed))
except:
print('-1 | -1')
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,23 @@
import sys
import board
from adafruit_emc2101.emc2101_lut import EMC2101_LUT as EMC2101
i2c = board.I2C() # uses board.SCL and board.SDA
FAN_MAX_RPM = 1700
emc = EMC2101(i2c)
def main():
# total arguments
n = len(sys.argv)
if n != 2:
print("No_duty_cycle_specified")
sys.exit(2)
dutyCycle=int(sys.argv[1])
emc.manual_fan_speed = dutyCycle
if __name__ == "__main__":
main()

View File

@@ -457,6 +457,33 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP
self.write_pwm(gpio, set_value)
return make_response('', 204)
@octoprint.plugin.BlueprintPlugin.route("/emc/<int:identifier>", methods=["PATCH"])
@restricted_access
def set_emc2101(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 'duty_cycle' not in data:
return make_response("missing duty_cycle attribute", 406)
set_value = self.to_int(data['duty_cycle'])
script = os.path.dirname(os.path.realpath(__file__)) + "/SETEMC2101.py"
cmd = [sys.executable, script, str(set_value)]
if self._settings.get(["use_sudo"]):
cmd.insert(0, "sudo")
stdout = Popen(cmd, stdout=PIPE, stderr=PIPE, universal_newlines=True)
output, errors = stdout.communicate()
if self._settings.get(["debug_temperature_log"]) is True:
if len(errors) > 0:
self._logger.error("EMC2101 error: %s", errors)
else:
self._logger.debug("EMC2101 result: %s", output)
self._logger.debug(output + " " + errors)
return make_response('', 204)
@octoprint.plugin.BlueprintPlugin.route("/rgb-led/<int:identifier>", methods=["PATCH"])
@restricted_access
def set_ledstrip_color(self, identifier):
@@ -835,6 +862,7 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP
self.handle_temp_hum_control()
self.handle_temperature_events()
self.handle_pwm_linked_temperature()
self.handle_emc_linked_temperature()
self.update_ui()
self.mqtt_sensor_topic = self.mqtt_root_topic + "/" + sensor['label']
self.mqtt_message = {"temperature": temp, "humidity": hum}
@@ -1006,6 +1034,10 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP
temp = self.read_18b20_temp(sensor['ds18b20_serial'])
hum = 0
airquality = 0
elif sensor['temp_sensor_type'] == "emc2101":
temp, hum = self.read_emc2101_temp(sensor['temp_sensor_address'], sensor['temp_sensor_i2cbus'])
hum =0
airquality = 0
elif sensor['temp_sensor_type'] == "bme280":
temp, hum = self.read_bme280_temp(sensor['temp_sensor_address'])
airquality = 0
@@ -1226,6 +1258,31 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP
"Failed to execute python scripts, try disabling use SUDO on advanced section of the plugin.")
self.log_error(ex)
return (0, 0)
def read_emc2101_temp(self, address, i2cbus):
try:
script = os.path.dirname(os.path.realpath(__file__)) + "/EMC2101.py"
cmd = [sys.executable, script, str(address), str(i2cbus)]
if self._settings.get(["use_sudo"]):
cmd.insert(0, "sudo")
if self._settings.get(["debug_temperature_log"]) is True:
self._logger.debug("Temperature EMC2101 cmd: %s", cmd)
stdout = Popen(cmd, stdout=PIPE, stderr=PIPE, universal_newlines=True)
output, errors = stdout.communicate()
if self._settings.get(["debug_temperature_log"]) is True:
if len(errors) > 0:
self._logger.error("EMC2101 error: %s", errors)
else:
self._logger.debug("EMC2101 result: %s", output)
temp, fanspeed = output.split("|")
print (temp + " , " + fanspeed )
return (self.to_float(temp.strip()), 0.0 )
except Exception as ex:
print(ex)
self._logger.info(
"Failed to execute python scripts, try disabling use SUDO on advanced section of the plugin.")
self.log_error(ex)
return (0, 0)
def read_aht10_temp(self, address, i2cbus):
try:
@@ -1346,6 +1403,55 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP
self.log_error(ex)
return 0
def handle_emc_linked_temperature(self):
try:
for pwm_output in list(filter(lambda item: item['output_type'] == 'emc',
self.rpi_outputs)):
if self._printer.is_printing():
index_id = self.to_int(pwm_output['index_id'])
linked_id = self.to_int(pwm_output['linked_temp_sensor'])
linked_data = self.get_linked_temp_sensor_data(linked_id)
current_temp = self.to_float(linked_data['temperature'])
duty_a = self.to_float(pwm_output['duty_a'])
duty_b = self.to_float(pwm_output['duty_b'])
temp_a = self.to_float(pwm_output['temperature_a'])
temp_b = self.to_float(pwm_output['temperature_b'])
try:
calculated_duty = ((current_temp - temp_a) * (duty_b - duty_a) / (temp_b - temp_a)) + duty_a
if current_temp < temp_a:
calculated_duty = 0
except:
calculated_duty = 0
self._logger.debug("Calculated duty for EMC %s is %s", index_id, calculated_duty)
elif self.print_complete:
calculated_duty = self.to_int(pwm_output['default_duty_cycle'])
else:
calculated_duty = self.to_int(pwm_output['default_duty_cycle'])
script = os.path.dirname(os.path.realpath(__file__)) + "/SETEMC2101.py"
cmd = [sys.executable, script, str(int(calculated_duty))]
if self._settings.get(["use_sudo"]):
cmd.insert(0, "sudo")
self._logger.info("Calculated fan speed is ", calculated_duty)
stdout = Popen(cmd, stdout=PIPE, stderr=PIPE, universal_newlines=True)
output, errors = stdout.communicate()
if self._settings.get(["debug_temperature_log"]) is True:
if len(errors) > 0:
self._logger.error("EMC2101 error: %s", errors)
else:
self._logger.debug("EMC2101 result: %s", output)
self._logger.debug(output + " " + errors)
except Exception as ex:
self.log_error(ex)
def handle_pwm_linked_temperature(self):
try:
for pwm_output in list(filter(lambda item: item['output_type'] == 'pwm' and item['pwm_temperature_linked'],

View File

@@ -22,6 +22,11 @@
<label class="radio">
<input type="radio" value="pwm" data-bind="checked: output_type, attr: {name: 'output_type_' + $index() }"> {{ _('PWM') }}
</label>
</div>
<div class="controls">
<label class="radio">
<input type="radio" value="emc" data-bind="checked: output_type, attr: {name: 'output_type_' + $index() }"> {{ _('EMC 2101') }}
</label>
</div>
<div class="controls">
<label class="radio">
@@ -91,7 +96,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" || ($data.output_type() == "regular" && $data.gpio_i2c_enabled())) -->
<!-- ko ifnot: ($data.output_type() == "gcode_output" || $data.output_type() == "temperature_alarm" || $data.output_type() == "emc" || $data.output_type() == "shell_output" || $data.output_type() == "ledstrip" || ($data.output_type() == "regular" && $data.gpio_i2c_enabled())) -->
<div class="control-group">
<label class="control-label">{{ _('IO Number') }}</label>
<div class="controls">
@@ -110,13 +115,13 @@
</div>
<!-- /ko -->
<!-- ko if: ($data.output_type() == "pwm" ) -->
<!-- ko if: (($data.output_type() == "pwm" ) || ($data.output_type() == "emc" )) -->
<div class="control-group">
<div class="controls">
<label class="checkbox">
<input type="checkbox" data-bind="checked: pwm_temperature_linked"> {{ _('Link PWM to Temperature') }}
<input type="checkbox" data-bind="checked: pwm_temperature_linked"> {{ _('Link PWM/EMC2101 to Temperature') }}
</label>
<span class="help-inline">Link PWM ouput to temperature. PWM output will be interpolated between the point from duty A, temperature A -> duty
<span class="help-inline">Link PWM/EMC2101 ouput to temperature. PWM/EMC2101 output will be interpolated between the point from duty A, temperature A -> duty
B, temperature B. This output will automatically start when a print starts and will default to the default
duty cycle when print is complete.
</span>
@@ -124,7 +129,7 @@
</div>
<!-- /ko -->
<!-- ko if: ($data.output_type() == "pwm" && $data.pwm_temperature_linked()) -->
<!-- ko if: (($data.output_type() == "pwm" || $data.output_type() == "emc") && $data.pwm_temperature_linked()) -->
<div class="control-group">
<label class="control-label">{{ _('Duty A') }}</label>
<div class="controls">
@@ -184,6 +189,7 @@
<!-- ko ifnot: (($data.output_type() == "regular" || $data.output_type() == "pwm") && $data.toggle_timer()) -->
<!-- ko ifnot: ($data.output_type() == "gcode_output" || $data.output_type() == "temperature_alarm" || $data.output_type() == "shell_output") -->
<!-- ko ifnot: ($data.output_type() == "pwm" && $data.pwm_temperature_linked()) -->
<!-- ko ifnot: ($data.output_type() == "emc") -->
<div class="control-group">
<div class="controls">
<label class="checkbox">
@@ -215,7 +221,8 @@
</div>
<!-- /ko -->
<!-- /ko -->
<!-- ko ifnot: ($data.output_type() == "gcode_output" || $data.output_type() == "temperature_alarm" || $data.output_type() == "shell_output") -->
<!-- /ko -->
<!-- ko ifnot: ($data.output_type() == "gcode_output" || $data.output_type() == "emc" || $data.output_type() == "temperature_alarm" || $data.output_type() == "shell_output") -->
<div class="control-group">
<div class="controls">
<label class="checkbox">
@@ -250,7 +257,7 @@
</div>
</div>
<!-- /ko -->
<!-- ko ifnot: ($data.output_type() == "gcode_output" || $data.output_type() == "temperature_alarm" || $data.output_type() == "shell_output") -->
<!-- ko ifnot: ($data.output_type() == "gcode_output" || $data.output_type() == "emc" || $data.output_type() == "temperature_alarm" || $data.output_type() == "shell_output") -->
<div class="control-group">
<div class="controls">
<label class="checkbox">
@@ -475,6 +482,15 @@
</div>
</div>
<!-- /ko -->
<!-- ko if: ($data.output_type() == "emc") -->
<div class="control-group">
<label class="control-label">{{ _('Default fan speed') }}</label>
<div class="controls">
<input type="text" class="input-block-level" data-bind="value: default_duty_cycle">
<span class="help-inline">Value is in percentage, between 0 and 100</span>
</div>
</div>
<!-- /ko -->
<!-- ko if: ($data.output_type() == "neopixel_indirect") -->
<div class="control-group">
<label class="control-label" for="settings-enclosure-dhtPin">{{ _('Microcontroller Address') }}</label>
@@ -612,6 +628,7 @@
<option value="bme680">BME680</option>
<option value="am2320">AM2320</option>
<option value="aht10">AHT10</option>
<option value="emc2101">EMC2101</option>
<option value="tmp102">TMP102</option>
<option value="max31855">MAX31855</option>
<option value="rpi">Raspberry Pi CPU</option>
@@ -731,7 +748,7 @@
</div>
<!-- /ko -->
<!-- ko ifnot: ($data.temp_sensor_type() == "rpi") || ($data.temp_sensor_type() == "18b20") || ($data.temp_sensor_type() == "si7021") || ($data.temp_sensor_type() == "bme280") || ($data.temp_sensor_type() == "am2320") || ($data.temp_sensor_type() == "tmp102") || ($data.temp_sensor_type() == "max31855") || ($data.temp_sensor_type() == "mcp9808") || ($data.temp_sensor_type() == "temp_raw_i2c") || ($data.temp_sensor_type() == "hum_raw_i2c") -->
<!-- ko ifnot: ($data.temp_sensor_type() == "rpi") || $data.temp_sensor_type() == "emc2101" || ($data.temp_sensor_type() == "18b20") || ($data.temp_sensor_type() == "si7021") || ($data.temp_sensor_type() == "bme280") || ($data.temp_sensor_type() == "am2320") || ($data.temp_sensor_type() == "tmp102") || ($data.temp_sensor_type() == "max31855") || ($data.temp_sensor_type() == "mcp9808") || ($data.temp_sensor_type() == "temp_raw_i2c") || ($data.temp_sensor_type() == "hum_raw_i2c") -->
<div class="control-group">
<label class="control-label" for="settings-enclosure-dhtPin">{{ _('Sensor Pin') }}</label>
<div class="controls">