Skip to content
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
2 changes: 1 addition & 1 deletion docs/develop/standardsguidelines.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ The 🐰 (see AI) will review each commit, please process the review recommendat

Before merging a PR back into main ask the 🐰 the following:

@coderabbitai, I am about to merge this PR, please do an in-depth review of all the commits made in this PR, make a summary, a recommendation to merge and a list of possible future actions.
@coderabbitai, I am about to merge this PR, please do an in-depth review of all the commits made in this PR, make a summary, a recommendation to merge and a list of possible future actions including a prompt for AI agents to look at the most urgent items before merge. Also make a prompt for AI agents to update end-user documentation (/docs) based on all changes in this PR. Please note the documentation is end-user documentation so end users don't have to know anything about the internals so make compact and user-friendly updates only describing usage implications of the changes made.

## Artificial Intelligence

Expand Down
10 changes: 6 additions & 4 deletions docs/moonbase/inputoutput.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,19 +80,21 @@ Toggling a switch **does not** set the modded flag — it reloads the board pres

| Control | Type | Options |
|---|---|---|
| **ethernetType** | Select | None, LAN8720 (RMII), W5500 (SPI) |
| **ethernetType** | Select | Board Default, LAN8720 (RMII), W5500 (SPI) |

Selects the ethernet hardware type. This is typically set automatically by the board preset but can be changed manually.

| Type | Interface | Chips | Available on |
|---|---|---|---|
| **None** | — | — | All targets |
| **Board Default** | Compile-time pins | Varies | Boards with ethernet defined in `pins_arduino.h` |
| **LAN8720 (RMII)** | Built-in EMAC | LAN8720A | ESP32-D0, ESP32-P4 |
| **W5500 (SPI)** | External SPI module | W5500, WIZ850IO | All targets |

RMII ethernet requires **ETH MDC**, **ETH MDIO**, and **ETH CLK** pins to be assigned. The six RMII data pins (TXD0, TX_EN, TXD1, RXD0, RXD1, CRS_DV) are hardwired in silicon and are reserved as **Ethernet** pin type.
**Board Default** uses the pin definitions baked into the board variant at compile time (via `pins_arduino.h`). No runtime pin assignment is needed — `ETH.begin()` is called with no arguments and the framework resolves the pins automatically. This is used by boards like the ESP32-P4-ETH where ethernet pins are fixed by the hardware design. If the board variant does not define ethernet pins, this option has no effect.

SPI ethernet requires **SPI SCK**, **SPI MISO**, **SPI MOSI**, and **PHY CS** pins to be assigned. **PHY IRQ** is optional.
**LAN8720 (RMII)** requires **ETH MDC**, **ETH MDIO**, and **ETH CLK** pins to be assigned. The six RMII data pins (TXD0, TX_EN, TXD1, RXD0, RXD1, CRS_DV) are hardwired in silicon and are reserved as **Ethernet** pin type.

**W5500 (SPI)** requires **SPI SCK**, **SPI MISO**, **SPI MOSI**, and **PHY CS** pins to be assigned. **PHY IRQ** is optional.

See [Ethernet settings](../../network/ethernet/) for hostname and IP configuration.

Expand Down
2 changes: 1 addition & 1 deletion docs/moonbase/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

* **Restart needed**: e.g. when drivers are changed, a restart might be needed, see 🔄 in the statusbar. Clicking on the 🔄 icon allows you to restart

* **Save** and **Cancel** Changes are only saved after pressing the save button 💾. To undo changes, press the cancel button ↻ and the last saved state will be restored.
* **Save** and **Cancel**: When there are unsaved changes, a Save button 💾 and a Cancel button ↻ appear. Save applies your changes permanently. Cancel discards the changes and restores the last saved state.

* **Theme**: Light, Dark, Auto

Expand Down
6 changes: 5 additions & 1 deletion docs/network/ethernet.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,8 @@

<img width="320" src="../../media/network/MB-ethernet.png" />

See [IO module](../../moonbase/inputoutput) to setup pins for Ethernet on S3 boards.
See [IO module](../../moonbase/inputoutput) to setup pins for Ethernet on S3 boards.

When Ethernet is connected, Wi‑Fi Station reconnection is suppressed on non‑PSRAM targets to save heap.
When Ethernet disconnects, Wi‑Fi reconnection is resumed by the normal STA management loop (not immediately in the Ethernet handler).
Access Point behavior depends on Provision Mode; it is not universally disabled by Ethernet state.
2 changes: 2 additions & 0 deletions docs/network/sta.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

<img width="320" src="../../media/network/MB-WiFi1.png" />

* **Hostname**: The hostname you set here is used as the device name everywhere in MoonLight: mDNS (for `.local` access), the Access Point name, and the name shown in the Devices module. Configure it once here and it applies across all network interfaces.

* **WiFi TX Power** 🌙: WiFi transmit power can be set to optimize WiFi behavior. Some boards are known to work better by setting transmit power to 8.5 dBM (So called LOLIN_WIFI_FIX).
* Default is typically 20 dBm (100mW) - the maximum allowed
* Common recommended settings:
Expand Down
4 changes: 3 additions & 1 deletion docs/system/status.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<img width="320" src="https://github.com/user-attachments/assets/ebbe9723-de0b-4fcf-a527-b660b508bb6e" />

* 🌙 **Performance**: loops per second: for effects, for drivers and overall. 🆕 Effects and drivers is the theoretical speed, if nothing else runs. overall lps is the really measured overall speed.
* 🌙 **Performance**: loops per second for effects, drivers and overall. The Effects and Drivers rows show the theoretical maximum loop speed for each task — the speed those tasks could reach if they were the only thing running. Actual speed (shown as lps) may be lower due to shared CPU time.
* 🌙 **Safe Mode**: After a crash, the device will start in Safe Mode disabling possible causes of crashes. See also [MoonLight](https://moonmodules.org/MoonLight/moonlight/overview/). In case of safe mode, the statusbar will show a shield: 🛡️. Try to find the reason of the crash and correct and restart the device. If no crash, it will go out of safe mode.
* 🌙 **Firmware Target**: Which firmware has been installed, see [MoonLight Installer](https://moonmodules.org/MoonLight/gettingstarted/installer/)
* 🌙 **Firmware Date**: What is the date the firmware is created (format YYYYMMDDHH)
Expand All @@ -11,3 +11,5 @@
* **Restart**: The device will restart
* **Factory reset**: all settings will be removed.

On ESP32-P4 boards with an onboard Wi-Fi coprocessor, the coprocessor firmware version is shown in System Status.

25 changes: 22 additions & 3 deletions interface/src/lib/components/moonbase/RowRenderer.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,26 @@
import Grip from '~icons/tabler/grip-vertical';
import FieldRenderer from './FieldRenderer.svelte';
import { isNumber } from 'chart.js/helpers';
import type { ModuleProperty, ModuleRow } from '$lib/types/moonbase_models';
import type { ModuleProperty, ModuleRow, ModuleData } from '$lib/types/moonbase_models';

let { property, data = $bindable(), definition, onChange, changeOnInput } = $props();
interface Props {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
property: any;
data: ModuleData;
definition: ModuleProperty[];
onChange: (event?: Event) => void;
onFilterChange?: (event?: Event) => void;
changeOnInput: boolean;
}

let {
property,
data = $bindable(),
definition,
onChange,
onFilterChange,
changeOnInput
}: Props = $props();

let dataEditable: ModuleRow = $state({});

Expand Down Expand Up @@ -188,8 +205,10 @@
property={propertyFilter}
bind:value={data[property.name + '_filter']}
noPrompts={false}
changeOnInput={false}
onChange={(event) => {
onChange(event);
if (onFilterChange) onFilterChange(event);
else onChange(event);
}}
></FieldRenderer>
{#if data[property.name + '_filter']}
Expand Down
39 changes: 28 additions & 11 deletions interface/src/lib/stores/telemetry.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { writable } from 'svelte/store';
import type { RSSI } from '../types/models';
import type { SystemStatus } from '../types/models'; // 🌙
import type { Battery } from '../types/models';
import type { OTAStatus } from '../types/models';
import type { Ethernet } from '../types/models';
Expand All @@ -8,11 +9,14 @@ let telemetry_data = {
rssi: {
rssi: 0,
ssid: '',
disconnected: true,
restartNeeded: false, // 🌙 restartNeeded Indicates if the system needs to be restarted
safeMode: false, // 🌙 safeMode Indicates if the system is in safe mode
saveNeeded: false, // 🌙 saveNeeded Indicates that changes has been made which need to be saved (or canceled)
hostName: "MoonLight" // 🌙 to show in title and statusbar
disconnected: true
},
// 🌙 System status — separate from rssi so it works on all boards (including ethernet-only)
status: {
safeMode: false,
restartNeeded: false,
saveNeeded: false,
hostName: localStorage.getItem('hostName') || 'MoonLight' // 🌙 persist across page loads
},
battery: {
soc: -1,
Expand Down Expand Up @@ -41,15 +45,28 @@ function createTelemetry() {
if (!isNaN(Number(data.rssi))) {
update((telemetry_data) => ({
...telemetry_data,
rssi: { rssi: Number(data.rssi), ssid: data.ssid, disconnected: false, safeMode: data.safeMode, restartNeeded: data.restartNeeded, saveNeeded: data.saveNeeded, hostName: data.hostName } // 🌙 variables added
rssi: { rssi: Number(data.rssi), ssid: data.ssid, disconnected: false }
}));
} else {
update((telemetry_data) => ({
...telemetry_data,
rssi: { rssi: 0, ssid: data.ssid, disconnected: true, safeMode: data.safeMode, restartNeeded: data.restartNeeded, saveNeeded: data.saveNeeded, hostName: data.hostName } // 🌙 variables added
rssi: { rssi: 0, ssid: data.ssid, disconnected: true }
}));
}
},
// 🌙 System status flags (saveNeeded, restartNeeded, safeMode, hostName)
setStatus: (data: SystemStatus) => {
if (data.hostName) localStorage.setItem('hostName', data.hostName); // 🌙 persist for next page load
update((telemetry_data) => ({
...telemetry_data,
status: {
safeMode: data.safeMode,
restartNeeded: data.restartNeeded,
saveNeeded: data.saveNeeded,
hostName: data.hostName
}
}));
},
setBattery: (data: Battery) => {
update((telemetry_data) => ({
...telemetry_data,
Expand All @@ -59,12 +76,12 @@ function createTelemetry() {
setOTAStatus: (data: OTAStatus) => {
update((telemetry_data) => ({
...telemetry_data,
ota_status: {
status: data.status,
progress: data.progress,
ota_status: {
status: data.status,
progress: data.progress,
bytes_written: data.bytes_written ?? 0,
total_bytes: data.total_bytes ?? 0,
error: data.error
error: data.error
}
}));
},
Expand Down
12 changes: 8 additions & 4 deletions interface/src/lib/types/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,14 @@ export type Analytics = {
export type RSSI = {
rssi: number;
ssid: string;
safeMode: boolean; // 🌙 safeMode Indicates if the system is in safe mode
restartNeeded: boolean; // 🌙 restartNeeded Indicates if the system needs to be restarted
saveNeeded: boolean; // 🌙 saveNeeded Indicates that changes has been made which need to be saved (or canceled)
hostName: string; // 🌙 to show in title and statusbar
};

// 🌙 System status flags — emitted independently of WiFi so they work on all boards
export type SystemStatus = {
safeMode: boolean;
restartNeeded: boolean;
saveNeeded: boolean;
hostName: string;
};

export type Battery = {
Expand Down
16 changes: 10 additions & 6 deletions interface/src/routes/+layout.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import Login from './login.svelte';
import type { Analytics } from '$lib/types/models';
import type { RSSI } from '$lib/types/models';
import type { SystemStatus } from '$lib/types/models'; // 🌙
import type { Battery } from '$lib/types/models';
import type { OTAStatus } from '$lib/types/models';
import Monitor from './moonbase/monitor/Monitor.svelte'; // 🌙
Expand Down Expand Up @@ -58,6 +59,7 @@
socket.on('close', handleClose);
socket.on('error', handleError);
socket.on('rssi', handleNetworkStatus);
socket.on('status', handleStatus); // 🌙
socket.on('notification', handleNotification);
if (page.data.features.analytics) socket.on('analytics', handleAnalytics);
if (page.data.features.battery) socket.on('battery', handleBattery);
Expand All @@ -71,7 +73,9 @@
socket.off('analytics', handleAnalytics);
socket.off('open', handleOpen);
socket.off('close', handleClose);
socket.off('error', handleError);
socket.off('rssi', handleNetworkStatus);
socket.off('status', handleStatus); // 🌙
socket.off('notification', handleNotification);
socket.off('battery', handleBattery);
socket.off('otastatus', handleOTA);
Expand Down Expand Up @@ -107,14 +111,13 @@
// if (!location.host.includes("captive.apple.com")) // 🌙 dirty workaround to not show this on macOS captive portal...
// notifications.error('Connection to device lost', 5000);
// $telemetry.rssi.disconnected = true; // 🌙
telemetry.setRSSI({
rssi: 0,
ssid: '',
telemetry.setRSSI({ rssi: 0, ssid: '' }); // 🌙
telemetry.setStatus({
safeMode: false,
restartNeeded: false,
saveNeeded: false,
hostName: 'MoonLight'
}); // 🌙 add safeMode etc
hostName: $telemetry.status.hostName || 'MoonLight'
}); // 🌙

socket.sendEvent('client_info', { visible: false }); // 🌙
};
Expand Down Expand Up @@ -143,6 +146,7 @@
const handleAnalytics = (data: Analytics) => analytics.addData(data);

const handleNetworkStatus = (data: RSSI) => telemetry.setRSSI(data);
const handleStatus = (data: SystemStatus) => telemetry.setStatus(data); // 🌙

const handleBattery = (data: Battery) => {
telemetry.setBattery(data);
Expand Down Expand Up @@ -177,7 +181,7 @@
</script>

<svelte:head>
<title>{$telemetry.rssi.hostName || 'MoonLight'}</title>
<title>{$telemetry.status.hostName || 'MoonLight'}</title>
</svelte:head>

{#if page.data.features.security && $user.bearer_token === ''}
Expand Down
4 changes: 2 additions & 2 deletions interface/src/routes/menu.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -135,13 +135,13 @@
title: 'WiFi Station',
icon: Router,
href: '/wifi/sta',
feature: true
feature: page.data.features.wifi // 🌙
},
{
title: 'Access Point',
icon: AP,
href: '/wifi/ap',
feature: true
feature: page.data.features.wifi // 🌙
},
{
title: 'Ethernet',
Expand Down
1 change: 1 addition & 0 deletions interface/src/routes/moonbase/module/Module.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@
bind:data
{definition}
onChange={(event: Event) => inputChanged(event, property.name)}
onFilterChange={(event: Event) => inputChanged(event, property.name + '_filter')}
changeOnInput={!modeWS}
></RowRenderer>
{/if}
Expand Down
2 changes: 2 additions & 0 deletions interface/src/routes/moonbase/monitor/Monitor.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { onMount, onDestroy } from 'svelte';
import {
clearColors,
clearVertices,
colors,
vertices,
createScene,
Expand Down Expand Up @@ -85,6 +86,7 @@

//rebuild scene
createScene(el);
clearVertices(); // clear old positions before receiving new ones

// let ledFactor: number = 1;//header[1];
// let ledSize: number = header[23];
Expand Down
13 changes: 5 additions & 8 deletions interface/src/routes/statusbar.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import { user } from '$lib/stores/user';
import ConfirmDialog from '$lib/components/ConfirmDialog.svelte';
import ThemeSelector from '$lib/components/ThemeSelector.svelte';
import WiFiOff from '~icons/tabler/wifi-off';
import Hamburger from '~icons/tabler/menu-2';
import Power from '~icons/tabler/power';
import Cancel from '~icons/tabler/x';
Expand Down Expand Up @@ -94,29 +93,29 @@
><Hamburger class="h-6 w-auto" /></label
>
<img src={logo} alt="Logo" class="h-12 w-12 lg:hidden" /> <!-- 🌙 -->
<span class="px-2 text-xl font-bold lg:text-2xl">{$telemetry.rssi.hostName || 'MoonLight'}</span> <!-- 🌙 -->
<span class="px-2 text-xl font-bold lg:text-2xl">{$telemetry.status.hostName || 'MoonLight'}</span> <!-- 🌙 -->
</div>
<div class="indicator flex-none">
<UpdateIndicator />
</div>
<!-- 🌙 safeMode -->
{#if $telemetry.rssi.safeMode}
{#if $telemetry.status.safeMode}
<div class="flex-none">
<button class="btn btn-square btn-ghost h-9 w-10" onclick={() => {confirmDialog("Restart", postRestart)}}>
🛡️
</button>
</div>
{/if}
<!-- 🌙 restartNeeded -->
{#if $telemetry.rssi.restartNeeded}
{#if $telemetry.status.restartNeeded}
<div class="flex-none">
<button class="btn btn-square btn-ghost h-9 w-10" onclick={() => {confirmDialog("Restart", postRestart)}}>
🔄
</button>
</div>
{/if}
<!-- 🌙 saveNeeded: save of cancel -->
{#if $telemetry.rssi.saveNeeded}
{#if $telemetry.status.saveNeeded}
<div class="flex-none">
<button class="btn btn-square btn-ghost h-9 w-10" onclick={postSaveConfig}>
💾
Expand All @@ -135,9 +134,7 @@
{#if page.data.features.ethernet && $telemetry.ethernet.connected}
<PlugConnected class="inline-block h-7 w-7" />
{/if}
{#if $telemetry.rssi.disconnected}
<WiFiOff class="inline-block h-7 w-7" />
{:else}
{#if !$telemetry.rssi.disconnected}
<RssiIndicator
showDBm={false}
rssi_dbm={$telemetry.rssi.rssi}
Expand Down
2 changes: 1 addition & 1 deletion interface/src/routes/system/status/SystemStatus.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@
<div>
<div class="font-bold">Performance</div>
<div class="text-sm opacity-75"> <!-- 🌙 -->
Effects: {systemInformation.lps_effects} lps &nbsp;|&nbsp; Drivers: {systemInformation.lps_drivers} lps &nbsp;➡&nbsp; All: {systemInformation.lps_all} lps
Effects: {systemInformation.lps_effects} max &nbsp;|&nbsp; Drivers: {systemInformation.lps_drivers} max &nbsp;➡&nbsp; All: {systemInformation.lps_all} lps
</div>
</div>
</div>
Expand Down
Loading
Loading