Event log

This commit is contained in:
cpq committed 2026-04-25 09:37:09 +01:00
1 parent 90051642ef
commit 8534053e57
9 files changed
+182 -96

No files matched your search

+1 -1
View File
@@ -4,7 +4,7 @@ PROG ?= example
MONGOOSE_DIR ?= ../..
SOURCES = main.c mongoose_dashboard.c dashboard.html.c $(MONGOOSE_DIR)/mongoose.c
CFLAGS ?= -W -Wall -Wextra -Werror -Wundef -Wshadow -g3 -O0
PFLAGS = -I$(MONGOOSE_DIR) -DMG_DATA_SIZE=64 -DMG_TLS=MG_TLS_BUILTIN
PFLAGS = -I$(MONGOOSE_DIR) -DMG_DATA_SIZE=64 -DMG_TLS=MG_TLS_BUILTIN -DMG_ENABLE_LINES=1
AFLAGS ?= -fsanitize=signed-integer-overflow,address,undefined,alignment
all: $(PROG)
+37 -14
View File
@@ -10,24 +10,24 @@
#endif
// Control panel
static bool s_fan, s_relay1, s_relay2;
static bool s_led1, s_led2, s_led3;
static struct mg_field fields_control[] = {
{"fan", MG_VAL_BOOL, &s_fan, sizeof(s_fan)},
{"relay1", MG_VAL_BOOL, &s_relay1, sizeof(s_relay1)},
{"relay2", MG_VAL_BOOL, &s_relay2, sizeof(s_relay2)},
static struct mg_field fields_leds[] = {
{"led1", MG_VAL_BOOL, &s_led1, sizeof(s_led1)},
{"led2", MG_VAL_BOOL, &s_led2, sizeof(s_led2)},
{"led3", MG_VAL_BOOL, &s_led3, sizeof(s_led3)},
{NULL, 0, NULL, 0},
};
static void sync_control(bool is_write) {
static void sync_leds(bool is_write) {
if (is_write) {
// gpio_write(FAN_PIN, s_fan);
// gpio_write(RELAY_1_PIN, s_relay1);
// gpio_write(RELAY_2_PIN, s_relay2);
// gpio_write(LED1_PIN, s_led1);
// gpio_write(LED2_PIN, s_led2);
// gpio_write(LED3_PIN, s_led3);
} else {
// s_fan = gpio_read(FAN_PIN);
// s_relay1 = gpio_read(RELAY_1_PIN);
// s_relay2 = gpio_read(RELAY_2_PIN);
// s_led1 = gpio_read(LED1_PIN);
// s_led2 = gpio_read(LED2_PIN);
// s_led3 = gpio_read(LED3_PIN);
}
}
@@ -107,16 +107,39 @@ void sync_chart1(bool is_write) {
len += mg_snprintf(s_chart1_data + len, sizeof(s_chart1_data) - len, "]");
}
static int s_num_log_files = 0;
static int s_log_file_index = 0;
static char s_log_file_name[100];
static struct mg_field fields_log_files[] = {
{"size", MG_VAL_INT, &s_num_log_files, sizeof(s_num_log_files)},
{"index", MG_VAL_INT, &s_log_file_index, sizeof(s_log_file_index)},
{"name", MG_VAL_STR, &s_log_file_name, sizeof(s_log_file_name)},
{NULL, 0, NULL, 0},
};
static void sync_log_files(bool is_write) {
if (is_write) return;
mg_log_level = s_log_level;
s_log_level = mg_log_level;
}
static struct mg_field_set field_sets[] = {
{"controls", fields_control, sync_control, 0, 0},
{"leds", fields_leds, sync_leds, 0, 0},
{"metrics", fields_metrics, sync_metrics, 0, 0},
{"settings", fields_settings, sync_settings, 0, 0},
{"chart1", fields_chart1, sync_chart1, 0, 0},
{"log_files", fields_log_files, sync_log_files, 0, 0},
{0, 0, 0, 0, 0},
};
static struct mg_dash s_dashboard = {field_sets};
static struct mg_dash s_dashboard = {field_sets, NULL};
static void log_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
if (ev == MG_EV_HTTP_MSG) {
mg_http_serve_file(c, ev_data, "Makefile", NULL);
}
}
void mg_dash_init(struct mg_mgr *mgr) {
MG_DASH_REGISTER_CUSTOM_HANDLER(&s_dashboard, "/logs/#", log_ev_handler);
mg_http_listen(mgr, HTTP_ADDR, mg_dash_ev_handler, &s_dashboard);
}
+17 -40
View File
@@ -10,22 +10,9 @@
debug: true,
data: {
chart1: {data: ''},
controls: {
fan: true,
relay1: false,
relay2: false,
},
settings: {
volume: 12,
log_level: 3,
name: 'Galway',
},
metrics: {
temperature: 1.2,
humidity: 3,
cpu: 4,
ram: 5,
},
leds: { led1: true, led2: false, led3: false },
settings: { volume: 12, log_level: 3, name: 'Galway' },
metrics: { temperature: 1.2, humidity: 3, cpu: 4, ram: 5 },
},
});
</script>
@@ -75,7 +62,7 @@
<path d="M8 17h5" />
<rect x="4" y="4" width="16" height="16" rx="3" />
</svg>
Events
Event Log
</a>
</nav>
</div>
@@ -175,30 +162,19 @@
<!-- Controls Panel -->
<div class="panel controls-panel">
<div class="panel-title">Controls</div>
<div class="panel-title">LED Control</div>
<div class="panel-body">
<div class="controls-list">
<div class="control-row">
<div class="control-info">
<div class="control-name">Cooling Fan</div>
<div class="control-desc">PWM controlled output</div>
</div>
<input type="checkbox" data-bind="controls.fan" data-autosave="1" class="toggle" />
</div>
<div class="control-row">
<div class="control-info">
<div class="control-name">Relay Channel 1</div>
<div class="control-desc">Auxiliary load output</div>
</div>
<input type="checkbox" data-bind="controls.relay1" data-autosave="1" class="toggle" />
</div>
<div class="control-row">
<div class="control-info">
<div class="control-name">Relay Channel 2</div>
<div class="control-desc">Safety-controlled line</div>
</div>
<input type="checkbox" data-bind="controls.relay2" data-autosave="1" class="toggle" />
</div>
<div class="field">
<div class="field-label">LED1</div>
<input type="checkbox" data-bind="leds.led1" data-autosave="1" class="toggle" />
</div>
<div class="field">
<div class="field-label">LED2</div>
<input type="checkbox" data-bind="leds.led2" data-autosave="1" class="toggle" />
</div>
<div class="field">
<div class="field-label">LED3</div>
<input type="checkbox" data-bind="leds.led3" data-autosave="1" class="toggle" />
</div>
</div>
</div>
@@ -236,6 +212,7 @@
</section>
<section id="firmware" class="tab-panel" role="tabpanel" aria-labelledby="tab-firmware" hidden></section>
<section id="events" class="tab-panel" role="tabpanel" aria-labelledby="tab-events" hidden>
<pre id="logs" class="file-content"></pre>
</section>
</main>
</body>
+4 -2
View File
@@ -86,6 +86,8 @@ document.addEventListener("DOMContentLoaded", () => {
Dashboard.on('change', args => updateGraphPoints(args?.chart1?.data));
Dashboard.call('get', 'chart1').then(resp => updateGraphPoints(resp?.data));
// Set iframe source in JS, to prevent Monolith killing it
document.getElementById("logs").src = "/logs/";
// Show logs
fetch('logs/')
.then(resp => resp.text())
.then(text => document.getElementById("logs").textContent = text);
});
+33 -3
View File
@@ -265,18 +265,19 @@ body {
.field {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
gap: 0.75rem;
}
.field-label {
font-size: 0.72rem;
font-size: 0.75rem;
font-weight: 700;
letter-spacing: 0.05em;
text-transform: uppercase;
color: #94a3b8;
width: 4.5rem;
flex-shrink: 0;
white-space: nowrap;
min-width: 6rem;
}
.field-input {
@@ -419,6 +420,35 @@ body {
flex-shrink: 0;
}
.file-content {
width: 100%;
min-height: calc(100vh - 7rem);
margin-top: 0.5rem;
padding: 1rem 1.15rem;
overflow: auto;
color: #dbeafe;
background:
linear-gradient(180deg, rgba(15, 23, 42, 0.96), rgba(15, 23, 42, 0.98)),
#0f172a;
border: 1px solid rgba(51, 65, 85, 0.9);
border-radius: 1rem;
box-shadow:
inset 0 1px 0 rgba(255, 255, 255, 0.08),
0 2px 6px rgba(15, 23, 42, 0.1),
0 12px 32px rgba(15, 23, 42, 0.14);
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
font-size: 0.82rem;
line-height: 1.55;
white-space: pre-wrap;
word-break: break-word;
tab-size: 2;
}
.file-content:empty::before {
content: "Waiting for events...";
color: #64748b;
}
/* Chart */
.chart-panel {