Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SW-4036 reset exhaust when external power plugged in #1829

Merged
merged 12 commits into from
Oct 19, 2023
7 changes: 7 additions & 0 deletions cypress/e2e/settings/maintenance.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@ describe("Maintenance", function () {
expect(resp.status).to.eq(200);
});
});
cy.get('[data-test="maintenance-links-buy-now-heavy-duty-pre-filter"]')
.invoke("attr", "href")
.then((myLink) => {
cy.request(myLink).then((resp) => {
expect(resp.status).to.eq(200);
});
});
});
// status code no exist
it("Air Filter: Main-filter", function () {
Expand Down
6 changes: 2 additions & 4 deletions octoprint_mrbeam/analytics/usage_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -979,11 +979,9 @@ def _calculate_af3_filter_usage(self, filter_stage):
logger = self._logger

# get the global values
pressure_loss = usage_data.get(
self.PRESSURE_KEY, AirFilter.MAX_PRESSURE_DIFFERENCE
)
pressure_loss = usage_data.get(self.PRESSURE_KEY, 0)
rpm_filter_test = self._get_airfilter_carbon_filter_usage_data().get(
self.FAN_TEST_RPM_KEY, AirFilter.MAX_FAN_TEST_RPM
self.FAN_TEST_RPM_KEY, 0
) # this is saved in carbon filter stage

# calculate the percentages
Expand Down
104 changes: 78 additions & 26 deletions octoprint_mrbeam/iobeam/airfilter.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from flask_babel import gettext

from octoprint_mrbeam.iobeam.iobeam_handler import IoBeamEvents
from octoprint_mrbeam.model.iobeam import exhaust

from octoprint_mrbeam.mrbeam_events import MrBeamEvents
from octoprint_mrbeam.mrb_logger import mrb_logger
Expand Down Expand Up @@ -50,8 +51,7 @@ class AirFilter(object):
FILTERSTAGES = [PREFILTER, CARBONFILTER]

PRESSURE_VALUES_LIST_SIZE = 5
MAX_PRESSURE_DIFFERENCE = 1880
MAX_FAN_TEST_RPM = 10750

AF3_MAX_PREFILTER_PRESSURE_CHANGE = (
100 # The maximum pressure change in Pa for the prefilter of the AF3
)
Expand All @@ -69,7 +69,7 @@ class AirFilter(object):
(950, 40),
(1150, 60),
(1500, 80),
(MAX_PRESSURE_DIFFERENCE, 100),
(1880, 100),
]
AF3_PRESSURE_GRAPH_PREFILTER = [
(100, 0),
Expand All @@ -83,7 +83,7 @@ class AirFilter(object):
(9860, 0),
(9900, 20),
(10200, 70),
(MAX_FAN_TEST_RPM, 100),
(10750, 100),
]

class ProfileParameters(Enum):
Expand Down Expand Up @@ -128,8 +128,33 @@ def __init__(self, plugin):
self._connected = None
self._last_pressure_values = deque(maxlen=self.PRESSURE_VALUES_LIST_SIZE)
self._profile = None
self._external_power = None
self._iobeam = None

self._load_current_profile()
self._event_bus.subscribe(
MrBeamEvents.MRB_PLUGIN_INITIALIZED, self._on_mrbeam_plugin_initialized
)

def reset_data(self):
"""Resets all data of the air filter."""
self._serial = None
self._model_id = None
self._pressure1 = None
self._pressure2 = None
self._pressure3 = None
self._pressure4 = None
self._temperature1 = None
self._temperature2 = None
self._temperature3 = None
self._temperature4 = None
self._profile = None
self._connected = None
self._last_pressure_values = deque(maxlen=self.PRESSURE_VALUES_LIST_SIZE)
self._external_power = None

def _on_mrbeam_plugin_initialized(self, event, payload):
self._iobeam = self._plugin.iobeam

@property
def model(self):
Expand Down Expand Up @@ -223,7 +248,10 @@ def set_airfilter(self, model_id, serial):

def _airfilter_changed(self):
self._plugin.send_mrb_state()
self._event_bus.fire(MrBeamEvents.AIRFILTER_CHANGED)
self._event_bus.fire(
MrBeamEvents.AIRFILTER_CHANGED,
{"model_id": self._model_id, "serial": self.serial},
)

def set_pressure(
self,
Expand Down Expand Up @@ -260,6 +288,29 @@ def set_pressure(
elif self._pressure1 is not None and self.model_id in self.AIRFILTER2_MODELS:
self._last_pressure_values.append(self._pressure1)

def set_device(self, device):
"""
Josef-MrBeam marked this conversation as resolved.
Show resolved Hide resolved
Sets the device data of the air filter.

Args:
device (exhaust.Device):

Returns:
None
"""
if (
self._external_power != device.ext_power
and device.ext_power
and device.serial_num == 0
):
self._logger.info(
"Exhaust fan is now connected to external power -> reset exhaust"
)
self._iobeam.reset_exhaust()
return None
Josef-MrBeam marked this conversation as resolved.
Show resolved Hide resolved
else:
self._external_power = device.ext_power

def _get_avg_pressure_differences(self):
"""Returns the average pressure differences of the last pressure readings.

Expand Down Expand Up @@ -296,7 +347,7 @@ def pressure_drop_mainfilter(self):
Returns:
int: Pressure drop of the main filter
"""
if self.model_id in self.AIRFILTER3_MODELS:
if self.is_airfilter3():
Josef-MrBeam marked this conversation as resolved.
Show resolved Hide resolved
(
_,
mainfilter_pressure_avg,
Expand All @@ -306,8 +357,17 @@ def pressure_drop_mainfilter(self):
return mainfilter_pressure_avg - fan_pressure_avg
return None

def is_airfilter3(self):
"""
Return True if the current air filter is an air filter 3

Returns:
bool: True if the current air filter is an air filter 3
"""
return self.model_id in self.AIRFILTER3_MODELS

def exhaust_hose_is_blocked(self):
if self.model_id in self.AIRFILTER3_MODELS:
if self.is_airfilter3():
return self._pressure2 < self.AF3_PRESSURE2_MIN
return None

Expand All @@ -318,7 +378,7 @@ def pressure_drop_prefilter(self):
Returns:
int: Pressure drop of the prefilter
"""
if self.model_id in self.AIRFILTER3_MODELS:
if self.is_airfilter3():
(
prefilter_pressure_avg,
mainfilter_pressure_avg,
Expand All @@ -330,6 +390,8 @@ def pressure_drop_prefilter(self):

@property
def connected(self):
if self.is_airfilter3() and not self._external_power:
return False
return self._connected

@connected.setter
Expand All @@ -346,7 +408,10 @@ def connected(self, connected):
if self._connected != connected:
self._connected = connected
if connected:
self._event_bus.fire(IoBeamEvents.FAN_CONNECTED)
self._event_bus.fire(
IoBeamEvents.FAN_CONNECTED,
{"serial": self.serial, "model_id": self.model_id},
)
# If the fan gets marked as connected but we don't have a serial number or model id
# Then the af used is a non smart => AF1 or single
if self.serial is None and self.model_id is None:
Expand All @@ -361,7 +426,10 @@ def connected(self, connected):
)
self._connected = connected # need to set it here again as the set_airfilter resets it
else:
self._event_bus.fire(IoBeamEvents.FAN_DISCONNECTED)
self._event_bus.fire(
IoBeamEvents.FAN_DISCONNECTED,
{"serial": self.serial, "model_id": self.model_id},
)

def set_temperatures(
self,
Expand All @@ -387,22 +455,6 @@ def set_temperatures(
if temperature4 is not None:
self._temperature4 = temperature4

def reset_data(self):
"""Resets all data of the air filter."""
self._serial = None
self._model_id = None
self._pressure1 = None
self._pressure2 = None
self._pressure3 = None
self._pressure4 = None
self._temperature1 = None
self._temperature2 = None
self._temperature3 = None
self._temperature4 = None
self._profile = None
self._connected = None
self._last_pressure_values = deque(maxlen=self.PRESSURE_VALUES_LIST_SIZE)

def _load_current_profile(self):
"""Loads the current profile of the air filter and safes it in self._profile.

Expand Down
25 changes: 17 additions & 8 deletions octoprint_mrbeam/iobeam/iobeam_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
HwMalfunction,
HwMalfunctionHandler,
)
from octoprint_mrbeam.model.iobeam import exhaust
from octoprint_mrbeam.mrb_logger import mrb_logger
from octoprint_mrbeam.lib.rwlock import RWLock
from flask.ext.babel import gettext
Expand Down Expand Up @@ -140,6 +141,7 @@ class IoBeamHandler(object):
MESSAGE_ACTION_FAN_TYPE = "type"
MESSAGE_ACTION_FAN_EXHAUST = "exhaust"
MESSAGE_ACTION_FAN_LINK_QUALITY = "link_quality"
MESSAGE_ACTION_EXHAUST_RESET = "reset"
MESSAGE_ACTION_COMPRESSOR_ON = "on"

# Possible datasets
Expand Down Expand Up @@ -232,6 +234,12 @@ def shutdown(self, *args):
def shutdown_fan(self):
self.send_fan_command(self.MESSAGE_ACTION_FAN_OFF)

def reset_exhaust(self):
"""
Reset the exhaust fan.
"""
self.send_fan_command(self.MESSAGE_ACTION_EXHAUST_RESET)

def is_interlock_closed(self):
return len(self._interlocks.keys()) == 0

Expand Down Expand Up @@ -1107,12 +1115,12 @@ def _handle_exhaust(self, dataset):
:param dataset:
:return: error count
"""
device_dataset = dataset.get("device", {})
device_dataset = exhaust.Device.from_dict(dataset.get("device", {}))
pressure_dataset = dataset.get("pressure", {})
temperature_dataset = dataset.get("temperature", {})
if (
device_dataset.get("serial_num") is None
and device_dataset.get("type") is None
device_dataset.serial_num is None
and device_dataset.type is None
and "error" in pressure_dataset
and "error" in temperature_dataset
):
Expand All @@ -1122,9 +1130,10 @@ def _handle_exhaust(self, dataset):
self._airfilter.set_airfilter(serial=self.UNKNOWN_SERIAL_KEY, model_id=1)
else:
self._airfilter.set_airfilter(
serial=device_dataset.get("serial_num"),
model_id=device_dataset.get("type"),
serial=device_dataset.serial_num,
model_id=device_dataset.type,
)
self._airfilter.set_device(device_dataset)
self._airfilter.set_pressure(
pressure1=pressure_dataset.get("pressure1"),
pressure2=pressure_dataset.get("pressure2"),
Expand All @@ -1138,10 +1147,10 @@ def _handle_exhaust(self, dataset):
temperature4=temperature_dataset.get("temp4"),
)
# get the pressure sensor reading this will come as dust with the current iobeam version
if "pressure" in device_dataset:
self._airfilter.set_pressure(pressure=device_dataset.get("pressure"))
if device_dataset:
self._airfilter.set_pressure(pressure=device_dataset.pressure)
vals = {
"pressure": device_dataset.get("pressure"),
"pressure": device_dataset.pressure,
}
self._call_callback(IoBeamValueEvents.EXHAUST_DYNAMIC_VALUE, dataset, vals)
return 0
Expand Down
Empty file.
67 changes: 67 additions & 0 deletions octoprint_mrbeam/model/iobeam/exhaust.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
class ExhaustModelInitializationError(Exception):
pass


class Device:
# FOR PYTHON3
# dataset_type: int
# ext_power: bool
# ext_voltage: float
# fan_power: float
# mode: str
# pressure: int
# serial_num: int
# smart_lock: bool
# type: int

def __init__(
self,
dataset_type,
ext_power,
ext_voltage,
fan_power,
mode,
pressure,
serial_num,
smart_lock,
type,
):
self.dataset_type = dataset_type
self.ext_power = ext_power
self.ext_voltage = ext_voltage
self.fan_power = fan_power
self.mode = mode
self.pressure = pressure
self.serial_num = serial_num
self.smart_lock = smart_lock
self.type = type

@staticmethod
# FOR PYTHON3
# def from_dict(dictonary: dict) -> Device:
def from_dict(dictonary):
"""
Josef-MrBeam marked this conversation as resolved.
Show resolved Hide resolved
Creates a Device object from a dict.

Args:
dictonary (dict): dict with the device data

Returns:
Device: Device object
"""
try:
return Device(
dictonary.get("dataset_type"),
dictonary.get("ext_power"),
dictonary.get("ext_voltage"),
dictonary.get("fan_power"),
dictonary.get("mode"),
dictonary.get("pressure"),
dictonary.get("serial_num"),
dictonary.get("smart_lock"),
dictonary.get("type"),
)
except TypeError as e:
raise ExhaustModelInitializationError(
"Can't init device from dict: {} - e:{}".format(dictonary, e)
)
Binary file modified octoprint_mrbeam/static/img/air_filter/af3-mainfilter.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,8 @@ $(function () {
if ("fan_connected" in mrb_state) {
if (mrb_state["fan_connected"] !== null) {
self.is_fan_connected(mrb_state["fan_connected"]);
} else {
self.is_fan_connected(false);
}
}
if ("rtl_mode" in mrb_state) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ $(function () {
let self = this;
window.mrbeam.viewModels["aboutSettingsViewModel"] = self;
self.mrb_state = params[0];
self.airfilter_serial = self.mrb_state.airfilter_serial;
self.airfilter_model = self.mrb_state.airfilter_model;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
{{ _('Please perform a homing cycle first') }}
</span>
</li>
<li>{{ _('Wait until the engraving is finished and Mr Beam Status Lights are green. Open the safety lid again and be carefult NOT to touch the engraved material. The camera will now take a picture of the engraving.') }}</li>
<li>{{ _('Wait until the engraving is finished and Mr Beam Status Lights are green. Open the safety lid again and be careful NOT to touch the engraved material. The camera will now take a picture of the engraving.') }}</li>
<li>{{ _('Start the calibration by clicking on the button, and then follow these steps:') }}
<ul>
<li>{{ _('Click on the arrow head of the marker in the magnified picture.') }}</li>
Expand Down
Loading