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-3833 fix 1027 error #1798

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
175 changes: 141 additions & 34 deletions octoprint_mrbeam/iobeam/dust_manager.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import time
import threading
from octoprint.events import Events as OctoPrintEvents
from octoprint.util import monotonic_time

from octoprint_mrbeam.iobeam.hw_malfunction_handler import HwMalfunctionHandler
from octoprint_mrbeam.mrbeam_events import MrBeamEvents
from octoprint_mrbeam.iobeam.iobeam_handler import IoBeamValueEvents, IoBeamEvents
from octoprint_mrbeam.mrb_logger import mrb_logger
from octoprint_mrbeam.util.errors import ErrorCodes
from collections import deque

# singleton
Expand Down Expand Up @@ -42,6 +46,8 @@ class DustManager(object):

FAN_TEST_RPM_PERCENTAGE = 50
FAN_TEST_DURATION = 35 # seconds
FAN_NOT_SPINNING_TIMEOUT = 10 # time in seconds before reporting the error
FAN_DATA_MISSING_TIMEOUT = 10 # time in seconds before reporting the error

def __init__(self, plugin):
self._plugin = plugin
Expand All @@ -58,7 +64,6 @@ def __init__(self, plugin):
self._connected = None
self._data_ts = 0

self._init_ts = time.time()
self._last_event = None
self._shutting_down = False
self._final_extraction_thread = None
Expand All @@ -70,6 +75,11 @@ def __init__(self, plugin):
self._fan_timers = []
self._last_command = dict(action=None, value=None)
self._just_initialized = False
self._fan_not_spinning_ts = None
self._fan_data_missing_ts = None
self._fan_data_missing_reported = None
self._fan_data_too_old_reported = None
Josef-MrBeam marked this conversation as resolved.
Show resolved Hide resolved
self._fan_not_spinning_reported = None

self._last_rpm_values = deque(maxlen=5)
self._last_pressure_values = deque(maxlen=5)
Expand Down Expand Up @@ -167,29 +177,22 @@ def _handle_exhaust_data(self, args):

def _handle_fan_data(self, args):
err = False
if args["state"] is not None:
self._state = args["state"]
else:
err = True
if args["dust"] is not None:
self._dust = args["dust"]
self._state = args.get("state")
self._dust = args.get("dust")
self._rpm = args.get("rpm")
self._connected = args.get("connected")

if self._printer.is_printing():
self._job_dust_values.append(self._dust)
else:
err = True
if args["rpm"] is not None:
self._rpm = args["rpm"]
else:
if self._rpm is None or self._state is None or self._dust is None:
err = True

self._connected = args["connected"]
if self._dust is not None and self._printer.is_printing():
self._job_dust_values.append(self._dust)

if self._connected is not None:
self._unboost_timer_interval()

if not err:
self._data_ts = time.time()
self._data_ts = monotonic_time()

self._validate_values()
self._send_dust_to_analytics(self._dust)
Expand Down Expand Up @@ -382,7 +385,7 @@ def __do_final_extraction_threaded(self):
self.is_final_extraction_mode = False
self._logger.debug(
"Final extraction: DUSTING_MODE_START end. duration was: %s",
time.time() - dust_start_ts,
monotonic_time() - dust_start_ts,
)
if self._continue_final_extraction:
self._start_final_extraction_phase2(
Expand Down Expand Up @@ -468,19 +471,24 @@ def _send_dust_to_analytics(self, val):
def _validate_values(self):
result = True
errs = []
if time.time() - self._data_ts > self.DEFAUL_DUST_MAX_AGE:
result = False
errs.append("data too old. age:{:.2f}".format(time.time() - self._data_ts))

if self._state is None:
result = False
errs.append("fan state:{}".format(self._state))
if self._rpm is None or self._rpm <= 0:
# check if one of the values is None
value_is_none_result, value_is_none_errs = self._check_if_one_value_is_none()
if not value_is_none_result:
result = False
errs.append("rpm:{}".format(self._rpm))
if self._dust is None:
errs.extend(value_is_none_errs)

# check if received data is too old
if monotonic_time() - self._data_ts > self.DEFAUL_DUST_MAX_AGE:
result = False
errs.append("dust:{}".format(self._dust))
errs.append(
"data too old. age:{:.2f}".format(monotonic_time() - self._data_ts)
)
else:
self._fan_data_too_old_reported = False

# check if fan is not spinning
self._check_if_fan_is_spinning_during_a_running_job()

if self._one_button_handler.is_printing() and self._state == 0:
self._logger.warn("Restarting fan since _state was 0 in printing state.")
Expand All @@ -495,16 +503,12 @@ def _validate_values(self):
rpm=self._rpm,
dust=self._dust,
connected=self._connected,
age=(time.time() - self._data_ts),
age=(monotonic_time() - self._data_ts),
)
)
self._pause_laser(
trigger=msg, analytics="invalid-old-fan-data", log_message=msg
trigger=msg, analytics="invalid-old-fan-data", log_message=log_message
)
if self._one_button_handler.is_printing():
self._plugin.hw_malfunction_handler.report_hw_malfunction(
{"err_fan_not_spinning": {"code": "E-00FF-1027"}},
)

elif self._connected == False:
result = False
Expand All @@ -513,13 +517,116 @@ def _validate_values(self):
rpm=self._rpm,
dust=self._dust,
connected=self._connected,
age=(time.time() - self._data_ts),
age=(monotonic_time() - self._data_ts),
)
self._pause_laser(trigger="Air filter not connected.", log_message=msg)

# TODO: check for error case in connected val (currently, connected == True/False/None)
self._check_and_report_error()
return result

def _check_if_one_value_is_none(self):
"""
Checks if one of the values is None and sets the _fan_data_missing_ts flag.

Returns: (bool, list): True if one of the values is None, False otherwise. And List of error messages.
"""
errs = []
result = False
if self._state is None or self._rpm is None or self._dust is None:
result = True
khaledsherkawi marked this conversation as resolved.
Show resolved Hide resolved
if self._fan_data_missing_ts is None:
self._fan_data_missing_ts = monotonic_time()
self._fan_data_missing_reported = False

if self._state is None:
errs.append("fan state:{}".format(self._state))

if self._dust is None:
errs.append("dust:{}".format(self._dust))

if self._rpm is None:
errs.append("rpm:{}".format(self._rpm))
else:
# reset counter or timer
self._fan_data_missing_ts = None
return result, errs
khaledsherkawi marked this conversation as resolved.
Show resolved Hide resolved

def _check_if_fan_is_spinning_during_a_running_job(self):
khaledsherkawi marked this conversation as resolved.
Show resolved Hide resolved
"""
Checks if the fan is not spinning during a running job and sets the _fan_not_spinning_ts flag.

Returns:
None
"""
if self._rpm <= 0 and self._one_button_handler.is_printing():
if self._fan_not_spinning_ts is None:
self._fan_not_spinning_ts = monotonic_time()
self._fan_not_spinning_reported = False
self._logger.warn(
"fan not spinning. rpm:{} since {:.2f}".format(
self._rpm, monotonic_time() - self._fan_not_spinning_ts
)
)
else:
self._fan_not_spinning_ts = None

def _check_and_report_error(self):
if not self._plugin.is_boot_grace_period():
if (
self._fan_not_spinning_ts is not None
and monotonic_time() - self._fan_not_spinning_ts
> self.FAN_NOT_SPINNING_TIMEOUT
and not self._fan_not_spinning_reported
):
self._logger.error("Fan is not spinning. Raising error to user.")
self._plugin.hw_malfunction_handler.report_hw_malfunction(
{
HwMalfunctionHandler.FAN_NOT_SPINNING: {
"code": ErrorCodes.E_1027,
"stop_laser": False, # don't cancel the laser job
}
},
)
self._fan_not_spinning_reported = True
self._pause_laser(
trigger="fan-not-spinning",
analytics="fan-not-spinning",
log_message="Fan is not spinning.",
)

if (
self._fan_data_missing_ts is not None
and monotonic_time() - self._fan_data_missing_ts
> self.FAN_DATA_MISSING_TIMEOUT
and not self._fan_data_missing_reported
):
self._logger.warn("Fan data is missing. Raising error to user.")
self._plugin.hw_malfunction_handler.report_hw_malfunction(
{
HwMalfunctionHandler.I2C_BUS_MALFUNCTION: {
"code": ErrorCodes.E_1030,
"stop_laser": False, # don't cancel the laser job
}
},
)
self._fan_data_missing_reported = True

if (
monotonic_time() - self._data_ts > self.DEFAUL_DUST_MAX_AGE
and not self._fan_data_too_old_reported
):
self._logger.warn("Fan data is to old. Raising error to user.")
self._plugin.hw_malfunction_handler.report_hw_malfunction(
{
HwMalfunctionHandler.I2C_BUS_MALFUNCTION: {
"code": ErrorCodes.E_1014,
"stop_laser": False, # don't cancel the laser job
}
},
)
self._fan_data_too_old_reported = True

def _validation_timer_callback(self):
try:
# self._request_value(self.DATA_TYPE_DYNAMIC)
Expand Down
10 changes: 10 additions & 0 deletions octoprint_mrbeam/static/js/app/view-models/user-notification.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ $(function () {
),
type: "error",
hide: false,
before_close: (pnotify) => self._dismissNotification(pnotify),
},
err_bottom_open: {
title: gettext("Bottom plate not detected"),
Expand All @@ -79,6 +80,7 @@ $(function () {
),
type: "error",
hide: false,
before_close: (pnotify) => self._dismissNotification(pnotify),
},
err_hardware_malfunction_i2c: {
title: gettext("Hardware malfunction"),
Expand All @@ -97,6 +99,7 @@ $(function () {
),
type: "error",
hide: false,
before_close: (pnotify) => self._dismissNotification(pnotify),
},
err_unknown_malfunction: {
title: gettext("Unknown malfunction"),
Expand All @@ -110,6 +113,7 @@ $(function () {
),
type: "error",
hide: false,
before_close: (pnotify) => self._dismissNotification(pnotify),
},
err_compressor_malfunction: {
title: gettext("Compressor malfunction"),
Expand All @@ -128,6 +132,7 @@ $(function () {
),
type: "error",
hide: false,
before_close: (pnotify) => self._dismissNotification(pnotify),
},
err_one_button_malfunction: {
title: gettext("One Button malfunction"),
Expand All @@ -143,6 +148,7 @@ $(function () {
),
type: "error",
hide: false,
before_close: (pnotify) => self._dismissNotification(pnotify),
},
err_interlock_malfunction: {
title: gettext("Interlock malfunction"),
Expand All @@ -161,6 +167,7 @@ $(function () {
),
type: "error",
hide: false,
before_close: (pnotify) => self._dismissNotification(pnotify),
},
warn_cam_conn_err: {
title: gettext("Camera busy"),
Expand Down Expand Up @@ -211,6 +218,7 @@ $(function () {
),
type: "error",
hide: false,
before_close: (pnotify) => self._dismissNotification(pnotify),
},
err_job_cancelled_due_to_internal_error: {
title: gettext("Laser job canceled"),
Expand Down Expand Up @@ -242,6 +250,7 @@ $(function () {
),
type: "error",
hide: false,
before_close: (pnotify) => self._dismissNotification(pnotify),
},
err_fan_not_spinning: {
title: gettext("Hardware malfunction"),
Expand All @@ -257,6 +266,7 @@ $(function () {
),
type: "error",
hide: false,
before_close: (pnotify) => self._dismissNotification(pnotify),
},
msg_cam_image_analytics_sent: {
title: gettext("Thank you"),
Expand Down
2 changes: 2 additions & 0 deletions octoprint_mrbeam/util/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,5 @@ class ErrorCodes:
E_1026 = "E-01FF-1026"
E_1027 = "E-00FF-1027"
E_1028 = "E-01FF-1028"
E_1029 = "E-00FF-1029"
E_1030 = "E-00FF-1030"
2 changes: 2 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,5 +64,7 @@ def mrbeam_plugin():
mrbeam_plugin._event_bus.fire(Events.STARTUP)
mrbeam_plugin.user_notification_system = MagicMock()
mrbeam_plugin._printer = MagicMock()
mrbeam_plugin.hw_malfunction_handler = MagicMock()
mrbeam_plugin.is_boot_grace_period = MagicMock(return_value=False)

yield mrbeam_plugin
Loading