Skip to content

Commit 32d7c05

Browse files
Merge pull request #372 from pollen-robotics/367-display-daemonbackend-error-in-dashboard
367 display daemon/backend error in dashboard
2 parents cf2e2d0 + 3112d1e commit 32d7c05

File tree

7 files changed

+127
-12
lines changed

7 files changed

+127
-12
lines changed

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ requires-python = ">=3.10"
1212
dependencies = [
1313
"numpy>=2.2.5",
1414
"scipy>=1.15.3, <2.0.0",
15-
"reachy_mini_motor_controller>=1.2.0",
15+
"reachy_mini_motor_controller>=1.3.0",
1616
"eclipse-zenoh>=1.4.0",
1717
"opencv-python<=5.0",
1818
"cv2_enumerate_cameras>=1.2.1",

src/reachy_mini/daemon/app/dashboard/static/js/daemon.js

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ const daemon = {
55
currentStatus: {},
66

77
start: async (wakeUp) => {
8-
fetch(`/api/daemon/start?wake_up=${wakeUp}`, {
8+
await fetch(`/api/daemon/start?wake_up=${wakeUp}`, {
99
method: 'POST',
1010
})
1111
.then((response) => {
@@ -23,7 +23,7 @@ const daemon = {
2323
},
2424

2525
stop: async (gotoSleep) => {
26-
fetch(`/api/daemon/stop?goto_sleep=${gotoSleep}`, {
26+
await fetch(`/api/daemon/stop?goto_sleep=${gotoSleep}`, {
2727
method: 'POST',
2828
})
2929
.then((response) => {
@@ -41,15 +41,11 @@ const daemon = {
4141
},
4242

4343
getStatus: async () => {
44-
fetch('/api/daemon/status')
44+
await fetch('/api/daemon/status')
4545
.then((response) => response.json())
4646
.then(async (data) => {
47-
let previousState = daemon.currentStatus.state;
4847
daemon.currentStatus = data;
49-
50-
if (previousState !== daemon.currentStatus.state) {
51-
await daemon.updateUI();
52-
}
48+
await daemon.updateUI();
5349
})
5450
.catch((error) => {
5551
console.error('Error fetching daemon status:', error);
@@ -65,7 +61,7 @@ const daemon = {
6561

6662
let currentState = daemon.currentStatus.state;
6763

68-
if (currentState === initialState || currentState === "starting" || currentState === "stopping") {
64+
if (currentState !== "error" && (currentState === initialState || currentState === "starting" || currentState === "stopping")) {
6965
setTimeout(() => {
7066
daemon.checkStatusUpdate(initialState);
7167
}, 500);
@@ -128,11 +124,12 @@ const daemon = {
128124
backendStatusText.textContent = 'Stopped';
129125
}
130126
else if (daemonState === 'error') {
131-
// daemonStatusAnim.setAttribute('data', '/static/assets/reachy-mini-ko-animation.svg');
132127
daemonStatusAnim.setAttribute('data', '/static/assets/no-wifi-cartoon.svg');
133128
toggleDaemonSwitch.checked = false;
134129
backendStatusIcon.classList.add('bg-red-500');
135130
backendStatusText.textContent = 'Error occurred';
131+
132+
notificationCenter.showError(daemon.currentStatus.error);
136133
}
137134

138135
await daemon.updateToggle();
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
const notificationCenter = {
2+
3+
showInfo: (message, duration = 5000, autoclose = true) => {
4+
notificationCenter.showNotification(message, false, duration, autoclose);
5+
},
6+
showError: (message, duration = 5000, autoclose = false) => {
7+
message = notificationCenter.errorTranslation(message);
8+
notificationCenter.showNotification(message, true, duration, autoclose);
9+
},
10+
11+
showNotification: (message, error, duration = 5000, autoclose = true) => {
12+
document.getElementById('notification-message').textContent = message;
13+
document.getElementById('notification-modal').style.display = 'block';
14+
15+
if (error) {
16+
document.getElementById('notification-content').classList.add('error');
17+
document.getElementById('notification-content').classList.remove('info');
18+
} else {
19+
document.getElementById('notification-content').classList.remove('error');
20+
document.getElementById('notification-content').classList.add('info');
21+
}
22+
23+
if (autoclose) {
24+
setTimeout(notificationCenter.closeNotification, duration);
25+
}
26+
},
27+
28+
closeNotification: () => {
29+
document.getElementById('notification-modal').style.display = 'none';
30+
},
31+
32+
errorTranslation: (errorMessage) => {
33+
if (errorMessage.includes('No Reachy Mini serial port found.')) {
34+
return 'Reachy Mini not detected on USB. Please check that the USB cable is properly connected.';
35+
}
36+
37+
console.log('No translation found for error message:', errorMessage);
38+
return errorMessage;
39+
},
40+
41+
};

src/reachy_mini/daemon/app/dashboard/tailwindcss/styles/app.css

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,4 +125,61 @@ body {
125125
font-family: 'Asap', sans-serif;
126126
font-weight: 400;
127127
color: rgba(0, 0, 0, 0.7);
128+
}
129+
130+
131+
.notification-modal {
132+
position: fixed;
133+
bottom: 24px;
134+
right: 24px;
135+
z-index: 9999;
136+
min-width: 300px;
137+
max-width: 400px;
138+
background: #fff;
139+
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);
140+
border-radius: 8px;
141+
display: none;
142+
animation: fadeInUp 0.3s;
143+
}
144+
145+
@keyframes fadeInUp {
146+
from {
147+
opacity: 0;
148+
transform: translateY(40px);
149+
}
150+
151+
to {
152+
opacity: 1;
153+
transform: translateY(0);
154+
}
155+
}
156+
157+
.notification-content {
158+
padding: 20px 28px;
159+
border-radius: 8px;
160+
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.15);
161+
display: flex;
162+
align-items: center;
163+
justify-content: space-between;
164+
}
165+
166+
/* Notification variants */
167+
.notification-content.info {
168+
background: #fff;
169+
border: 1px solid #e0e0e0;
170+
}
171+
172+
.notification-content.error {
173+
background: #ffeaea;
174+
border: 1px solid #ff4d4f;
175+
color: #b71c1c;
176+
}
177+
178+
179+
.close-btn {
180+
background: none;
181+
border: none;
182+
font-size: 1.5em;
183+
cursor: pointer;
184+
color: #888;
128185
}

src/reachy_mini/daemon/app/dashboard/templates/index.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
{% include "sections/daemon.html" %}
77
{% include "sections/apps.html" %}
88
{% include "sections/appstore.html" %}
9+
{% include "sections/notification.html" %}
910
</div>
1011
{% endblock %}
1112

@@ -14,4 +15,5 @@
1415
<script src="/static/js/apps.js"></script>
1516
<script src="/static/js/appstore.js"></script>
1617
<script src="/static/js/move_player.js"></script>
18+
<script src="/static/js/notification.js"></script>
1719
{% endblock %}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<!-- Notification Modal (Bottom Right) -->
2+
<div id="notification-modal" class="notification-modal">
3+
<div class="notification-content" id="notification-content">
4+
<!-- Notification message will appear here -->
5+
<span id="notification-message"></span>
6+
<button class="close-btn" onclick="closeNotification()">×</button>
7+
</div>
8+
</div>
9+
10+
<script>
11+
function showNotification(message) {
12+
document.getElementById('notification-message').textContent = message;
13+
document.getElementById('notification-modal').style.display = 'block';
14+
setTimeout(closeNotification, 5000); // Auto-close after 5s
15+
}
16+
function closeNotification() {
17+
document.getElementById('notification-modal').style.display = 'none';
18+
}
19+
</script>

src/reachy_mini/daemon/backend/robot/backend.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,6 @@ def _update(self) -> None:
216216
self.ready.set() # Mark the backend as ready
217217
except RuntimeError as e:
218218
self._stats["nb_error"] += 1
219-
# self.logger.warning(f"Error reading positions: {e}")
220219

221220
assert self.last_alive is not None
222221

0 commit comments

Comments
 (0)