Skip to content

Commit

Permalink
SW-3054 mvp fire detection (#1730)
Browse files Browse the repository at this point in the history
* add high temperature warning
* add high temperature handling in analytics, printer, leds, compressor and exhaust
* play sound on message show
* ignore led events on high_temperature_warning except shutdown
* bumped analytics version
* only play sound if it was not played in the last 5 minutes
* add translation

---------

Co-authored-by: Ahmed Salem <[email protected]>
  • Loading branch information
Josef-MrBeam and ahmed-mrbeam authored Mar 30, 2023
1 parent 21021c2 commit 1b83b9e
Show file tree
Hide file tree
Showing 24 changed files with 568 additions and 52 deletions.
20 changes: 20 additions & 0 deletions octoprint_mrbeam/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -756,6 +756,7 @@ def get_assets(self):
"js/app/view-models/settings/calibration/watterott/calibration-qa.js",
"js/app/view-models/settings/calibration/watterott/label-printer.js",
"js/app/view-models/modal/hard_refresh_overlay.js",
"js/app/view-models/modal/temperature_warning.js",
"js/app/view-models/mrbeam-simple-api-commands.js",
"js/app/view-models/mrbeam-constants.js",
"js/app/helpers/mutation-observer.js",
Expand Down Expand Up @@ -1367,6 +1368,19 @@ def handle_pep440_comparison_result(self, data):
self._logger.error("Key is missing in data: %s", e)
return make_response(json.dumps(None), 500)

# simpleApiCommand: dismiss_temperature_warning;
def handle_temperature_warning_dismissal(self, data):
self.temperature_manager.dismiss_high_temperature_warning()
return NO_CONTENT

# simpleApiCommand: temperature_warning_status;
def return_temperature_warning_status(self, data):
return jsonify(
dict(
high_temperature_warning=self.temperature_manager.high_temperature_warning
)
)

# ~~ helpers

# helper method to write data to user settings
Expand Down Expand Up @@ -2001,6 +2015,8 @@ def get_api_commands(self):
generate_calibration_markers_svg=[],
cancel_final_extraction=[],
compare_pep440_versions=[],
dismiss_temperature_warning=[],
temperature_warning_status=[],
)

def on_api_command(self, command, data):
Expand Down Expand Up @@ -2130,6 +2146,10 @@ def on_api_command(self, command, data):
self.dust_manager.set_user_abort_final_extraction()
elif command == "compare_pep440_versions":
return self.handle_pep440_comparison_result(data)
elif command == "dismiss_temperature_warning":
return self.handle_temperature_warning_dismissal(data)
elif command == "temperature_warning_status":
return self.return_temperature_warning_status(data)

return NO_CONTENT

Expand Down
96 changes: 94 additions & 2 deletions octoprint_mrbeam/analytics/analytics_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def analyticsHandler(plugin):
class AnalyticsHandler(object):
QUEUE_MAXSIZE = 1000
ANALYTICS_LOG_VERSION = (
26 # bumped for SW-2465 add laserhead changed event to analytics
27 # bumped for SW-3054 add high temperature warning and abort laser job
)

def __init__(self, plugin):
Expand Down Expand Up @@ -114,6 +114,7 @@ def _on_mrbeam_plugin_initialized(self, event, payload):
_ = payload
self._laserhead_handler = self._plugin.laserhead_handler
self._dust_manager = self._plugin.dust_manager
self._temperature_manager = self._plugin.temperature_manager
self._compressor_handler = self._plugin.compressor_handler

self._subscribe()
Expand Down Expand Up @@ -729,13 +730,27 @@ def _subscribe(self):
self._event_bus.subscribe(
MrBeamEvents.LASER_JOB_FAILED, self._event_laser_job_finished
)
self._event_bus.subscribe(
MrBeamEvents.LASER_JOB_ABORTED, self._event_laser_job_finished
)
self._event_bus.subscribe(OctoPrintEvents.SHUTDOWN, self._event_shutdown)
self._event_bus.subscribe(
MrBeamEvents.ANALYTICS_DATA, self._add_other_plugin_data
)
self._event_bus.subscribe(
MrBeamEvents.JOB_TIME_ESTIMATED, self._event_job_time_estimated
)
self._event_bus.subscribe(
MrBeamEvents.PRINT_ABORTED, self._on_event_print_aborted
)
self._event_bus.subscribe(
MrBeamEvents.HIGH_TEMPERATURE_WARNING,
self._on_event_high_temperature_warning,
)
self._event_bus.subscribe(
MrBeamEvents.HIGH_TEMPERATURE_WARNING_DISMISSED,
self._on_event_high_temperature_warning_dismissed,
)

def _event_startup(self, event, payload, header_extension=None):
_ = event
Expand Down Expand Up @@ -939,7 +954,6 @@ def _event_print_done(self, event, payload, header_extension=None):
self._add_cpu_data(dur=payload["time"], header_extension=header_extension)

def _event_print_failed(self, event, payload, header_extension=None):
_ = event
details = {
AnalyticsKeys.Job.Duration.CURRENT: int(round(payload["time"])),
AnalyticsKeys.Job.ERROR: payload["error_msg"],
Expand All @@ -964,6 +978,31 @@ def _event_print_cancelled(self, event, payload, header_extension=None):
self._add_collector_details()
self._add_cpu_data(dur=payload["time"])

def _on_event_print_aborted(self, event, payload, header_extension=None):
"""Callback for aborted print event . Will add an event to analytics.
Args:
event: event that triggered the action
payload: payload of the event
header_extension: extension for the header
Returns:
None
"""
_ = event
trigger = payload.get("trigger", None)

self._current_job_final_status = "Aborted"
self._add_job_event(
AnalyticsKeys.Job.Event.Print.ABORTED,
payload={
AnalyticsKeys.Job.TRIGGER: trigger,
},
header_extension=header_extension,
)
self._add_collector_details()
self._add_cpu_data(dur=payload.get("time"))

def _event_laser_job_finished(self, event, payload, header_extension=None):
_ = event
_ = payload
Expand Down Expand Up @@ -1054,6 +1093,59 @@ def _add_other_plugin_data(self, event, event_payload, header_extension=None):
"Exception during _add_other_plugin_data: {}".format(e)
)

def _on_event_high_temperature_warning(self, event, payload, header_extension=None):
"""Callback for high temperature warning event. Will add an event to analytics with the current temperature and the set threshold for triggering the user warning.
Args:
event: event that triggered this action
payload: payload of the event
header_extension: extension to the header
Returns:
None
"""
_ = event
try:
self._add_device_event(
AnalyticsKeys.Device.HighTempWarning.TRIGGERED,
payload=dict(
temperature=payload.get("tmp", 0),
threshold=self._temperature_manager.high_tmp_warn_threshold,
),
header_extension=header_extension,
)
except Exception as e:
self._logger.exception(
"Exception during on_event_high_temperature_warning: {}".format(e)
)

def _on_event_high_temperature_warning_dismissed(
self, event, payload, header_extension=None
):
"""Callback for high temperature warning dismissed event. Will add an event to analytics."
Args:
event: event that triggered this action
payload: payload of the event
header_extension: extension to the header
Returns:
None
"""
_ = event
_ = payload
try:
self._add_device_event(
AnalyticsKeys.Device.HighTempWarning.DISMISSED,
header_extension=header_extension,
)
except Exception as e:
self._logger.exception(
"Exception during on_event_high_temperature_warning_dismissed: {}".format(
e
)
)

# -------- ANALYTICS LOGS QUEUE ------------------------------------------------------------------------------------
def _add_device_event(self, event, payload=None, header_extension=None):
self._add_event_to_queue(
Expand Down
6 changes: 6 additions & 0 deletions octoprint_mrbeam/analytics/analytics_keys.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class Job:
ID = "job_id"
ERROR = "err"
STATUS = "status"
TRIGGER = "trigger"

class Event:
LASERJOB_STARTED = "laserjob_started"
Expand All @@ -52,6 +53,7 @@ class Print:
RESUMED = "p_resumed"
CANCELLED = "p_cancelled"
FAILED = "p_failed"
ABORTED = "p_aborted"
DONE = "p_done"

class Cooling:
Expand Down Expand Up @@ -117,6 +119,10 @@ class Event:
CAMERA_IMAGE = "camera_image"
LASERHEAD_CHANGED = "laserhead_changed"

class HighTempWarning:
TRIGGERED = "high_temp_warning_triggered"
DISMISSED = "high_temp_warning_dismissed"

class SoftwareChannel:
OLD = "old_channel"
NEW = "new_channel"
Expand Down
7 changes: 7 additions & 0 deletions octoprint_mrbeam/iobeam/compressor_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ def _subscribe(self):
self._event_bus.subscribe(
OctoPrintEvents.PRINT_RESUMED, self.set_compressor_unpause
)
self._event_bus.subscribe(
MrBeamEvents.HIGH_TEMPERATURE_WARNING, self._on_high_temperature_warning
)

def has_compressor(self):
return self._plugin._device_info.is_mrbeam2_dc_series()
Expand Down Expand Up @@ -211,3 +214,7 @@ def get_compressor_data(self):
)

return data

def _on_high_temperature_warning(self, event, payload):
self._logger.info("High temperature Warning triggered, turning off compressor")
self.set_compressor_off()
4 changes: 4 additions & 0 deletions octoprint_mrbeam/iobeam/dust_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ def _subscribe(self):
self._event_bus.subscribe(IoBeamEvents.CONNECT, self._onEvent)
self._event_bus.subscribe(MrBeamEvents.READY_TO_LASER_CANCELED, self._onEvent)
self._event_bus.subscribe(MrBeamEvents.BUTTON_PRESS_REJECT, self._onEvent)
self._event_bus.subscribe(MrBeamEvents.HIGH_TEMPERATURE_WARNING, self._onEvent)
self._event_bus.subscribe(OctoPrintEvents.SLICING_DONE, self._onEvent)
self._event_bus.subscribe(OctoPrintEvents.PRINT_STARTED, self._onEvent)
self._event_bus.subscribe(OctoPrintEvents.PRINT_DONE, self._onEvent)
Expand Down Expand Up @@ -247,6 +248,9 @@ def _onEvent(self, event, payload):
elif event == IoBeamEvents.LID_OPENED:
if self.is_final_extraction_mode:
self.set_user_abort_final_extraction()
elif event == MrBeamEvents.HIGH_TEMPERATURE_WARNING:
self._logger.info("High temperature warning triggered, turning off exhaust")
self._stop_dust_extraction()

def _start_test_fan_rpm(self):
self._logger.debug(
Expand Down
35 changes: 35 additions & 0 deletions octoprint_mrbeam/iobeam/laserhead_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
MODEL_MRBEAM_2_DC_R1, MODEL_MRBEAM_2_DC_R2, MODEL_MRBEAM_2

LASERHEAD_MAX_TEMP_FALLBACK = 55.0
LASERHEAD_HIGH_TMP_WARN_OFFSET_FALLBACK = 2.0
LASERHEAD_MAX_DUST_FACTOR_FALLBACK = 3.0 # selected the highest factor
LASERHEAD_MAX_CORRECTION_FACTOR_FALLBACK = 1
LASERHEAD_MAX_INSTENSITY_INCLUDING_CORRECTION_FALLBACK = 1500
Expand Down Expand Up @@ -496,6 +497,40 @@ def default_laserhead_max_temperature(self):

return LASERHEAD_MAX_TEMP_FALLBACK

@property
def current_laserhead_high_temperature_warn_offset(self):
"""Return the current laser head high temperature warn offset.
Returns:
float: Laser head high tmp warn offset
"""
current_laserhead_properties = self._get_laserhead_properties()

# Handle the exceptions
if ((isinstance(current_laserhead_properties, dict) is False) or
("high_temperature_offset" not in current_laserhead_properties) or
(isinstance(current_laserhead_properties["high_temperature_offset"], float) is False)):
# Apply fallback
self._logger.debug("Current laserhead properties: {}".format(current_laserhead_properties))
self._logger.exception(
"Current Laserhead high temperature warn offset couldn't be retrieved, fallback to the temperature value of: {}".format(
self.default_laserhead_high_temperature_warn_offset))
return self.default_laserhead_high_temperature_warn_offset
# Reaching here means, everything looks good
self._logger.debug("Current Laserhead high temperature warn offset:{}".format(current_laserhead_properties["high_temperature_offset"]))
return current_laserhead_properties["high_temperature_offset"]

@property
def default_laserhead_high_temperature_warn_offset(self):
"""Default high temperature warning offset for laser head. to be used by other modules
at init time.
Returns:
float: Laser head default high tmp warn offset
"""

return LASERHEAD_HIGH_TMP_WARN_OFFSET_FALLBACK

def _load_current_laserhead_properties(self):
"""Loads the current detected laser head related properties from the
laser head profile files and return them.
Expand Down
Loading

0 comments on commit 1b83b9e

Please sign in to comment.