mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2026-01-29 01:59:08 +03:00
optimizations
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
import { type FC, memo, useMemo } from 'react';
|
||||
|
||||
import AutoAwesomeMotionIcon from '@mui/icons-material/AutoAwesomeMotion';
|
||||
import DeviceHubIcon from '@mui/icons-material/DeviceHub';
|
||||
import ReportIcon from '@mui/icons-material/Report';
|
||||
@@ -22,17 +24,28 @@ import type { MqttStatusType } from 'types';
|
||||
import { MqttDisconnectReason } from 'types';
|
||||
import { useInterval } from 'utils';
|
||||
|
||||
// Disconnect reason lookup table - created once, reused across renders
|
||||
const DISCONNECT_REASONS: Record<MqttDisconnectReason, string> = {
|
||||
[MqttDisconnectReason.USER_OK]: 'User disconnected',
|
||||
[MqttDisconnectReason.TCP_DISCONNECTED]: 'TCP disconnected',
|
||||
[MqttDisconnectReason.MQTT_UNACCEPTABLE_PROTOCOL_VERSION]:
|
||||
'Unacceptable protocol version',
|
||||
[MqttDisconnectReason.MQTT_IDENTIFIER_REJECTED]: 'Client ID rejected',
|
||||
[MqttDisconnectReason.MQTT_SERVER_UNAVAILABLE]: 'Server unavailable',
|
||||
[MqttDisconnectReason.MQTT_MALFORMED_CREDENTIALS]: 'Malformed credentials',
|
||||
[MqttDisconnectReason.MQTT_NOT_AUTHORIZED]: 'Not authorized',
|
||||
[MqttDisconnectReason.TLS_BAD_FINGERPRINT]: 'TLS fingerprint invalid'
|
||||
};
|
||||
|
||||
const getDisconnectReason = (disconnect_reason: MqttDisconnectReason): string =>
|
||||
DISCONNECT_REASONS[disconnect_reason] ?? 'Unknown';
|
||||
|
||||
export const mqttStatusHighlight = (
|
||||
{ enabled, connected }: MqttStatusType,
|
||||
theme: Theme
|
||||
) => {
|
||||
if (!enabled) {
|
||||
return theme.palette.info.main;
|
||||
}
|
||||
if (connected) {
|
||||
return theme.palette.success.main;
|
||||
}
|
||||
return theme.palette.error.main;
|
||||
if (!enabled) return theme.palette.info.main;
|
||||
return connected ? theme.palette.success.main : theme.palette.error.main;
|
||||
};
|
||||
|
||||
export const mqttPublishHighlight = (
|
||||
@@ -41,114 +54,100 @@ export const mqttPublishHighlight = (
|
||||
) => {
|
||||
if (mqtt_fails === 0) return theme.palette.success.main;
|
||||
if (mqtt_fails < 10) return theme.palette.warning.main;
|
||||
|
||||
return theme.palette.error.main;
|
||||
};
|
||||
|
||||
export const mqttQueueHighlight = (
|
||||
{ mqtt_queued }: MqttStatusType,
|
||||
theme: Theme
|
||||
) => {
|
||||
if (mqtt_queued <= 1) return theme.palette.success.main;
|
||||
export const mqttQueueHighlight = ({ mqtt_queued }: MqttStatusType, theme: Theme) =>
|
||||
mqtt_queued <= 1 ? theme.palette.success.main : theme.palette.warning.main;
|
||||
|
||||
return theme.palette.warning.main;
|
||||
};
|
||||
interface ConnectionStatusProps {
|
||||
data: MqttStatusType;
|
||||
theme: Theme;
|
||||
}
|
||||
|
||||
// Memoized component to prevent unnecessary re-renders when parent updates
|
||||
const ConnectionStatus: FC<ConnectionStatusProps> = memo(({ data, theme }) => {
|
||||
const { LL } = useI18nContext();
|
||||
|
||||
return (
|
||||
<>
|
||||
{!data.connected && (
|
||||
<>
|
||||
<ListItem>
|
||||
<ListItemAvatar>
|
||||
<Avatar>
|
||||
<ReportIcon />
|
||||
</Avatar>
|
||||
</ListItemAvatar>
|
||||
<ListItemText
|
||||
primary={LL.DISCONNECT_REASON()}
|
||||
secondary={getDisconnectReason(data.disconnect_reason)}
|
||||
/>
|
||||
</ListItem>
|
||||
<Divider variant="inset" component="li" />
|
||||
</>
|
||||
)}
|
||||
<ListItem>
|
||||
<ListItemAvatar>
|
||||
<Avatar>#</Avatar>
|
||||
</ListItemAvatar>
|
||||
<ListItemText primary={LL.ID_OF(LL.CLIENT())} secondary={data.client_id} />
|
||||
</ListItem>
|
||||
<Divider variant="inset" component="li" />
|
||||
<ListItem>
|
||||
<ListItemAvatar>
|
||||
<Avatar sx={{ bgcolor: mqttQueueHighlight(data, theme) }}>
|
||||
<AutoAwesomeMotionIcon />
|
||||
</Avatar>
|
||||
</ListItemAvatar>
|
||||
<ListItemText primary={LL.MQTT_QUEUE()} secondary={data.mqtt_queued} />
|
||||
</ListItem>
|
||||
<Divider variant="inset" component="li" />
|
||||
<ListItem>
|
||||
<ListItemAvatar>
|
||||
<Avatar sx={{ bgcolor: mqttPublishHighlight(data, theme) }}>
|
||||
<SpeakerNotesOffIcon />
|
||||
</Avatar>
|
||||
</ListItemAvatar>
|
||||
<ListItemText primary={LL.ERRORS_OF('MQTT')} secondary={data.mqtt_fails} />
|
||||
</ListItem>
|
||||
<Divider variant="inset" component="li" />
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
||||
const MqttStatus = () => {
|
||||
const { data, send: loadData, error } = useRequest(MqttApi.readMqttStatus);
|
||||
const { LL } = useI18nContext();
|
||||
const theme = useTheme();
|
||||
|
||||
useLayoutTitle('MQTT');
|
||||
|
||||
useInterval(() => {
|
||||
void loadData();
|
||||
});
|
||||
|
||||
const { LL } = useI18nContext();
|
||||
useLayoutTitle('MQTT');
|
||||
// Memoize error message separately to avoid re-renders on error object changes
|
||||
const errorMessage = error?.message || '';
|
||||
|
||||
const theme = useTheme();
|
||||
|
||||
const mqttStatus = ({ enabled, connected, connect_count }: MqttStatusType) => {
|
||||
if (!enabled) {
|
||||
return LL.NOT_ENABLED();
|
||||
}
|
||||
if (connected) {
|
||||
return LL.CONNECTED(0) + ' (' + connect_count + ')';
|
||||
}
|
||||
return LL.DISCONNECTED() + ' (' + connect_count + ')';
|
||||
};
|
||||
|
||||
const disconnectReason = ({ disconnect_reason }: MqttStatusType) => {
|
||||
switch (disconnect_reason) {
|
||||
case MqttDisconnectReason.TCP_DISCONNECTED:
|
||||
return 'TCP disconnected';
|
||||
case MqttDisconnectReason.MQTT_UNACCEPTABLE_PROTOCOL_VERSION:
|
||||
return 'Unacceptable protocol version';
|
||||
case MqttDisconnectReason.MQTT_IDENTIFIER_REJECTED:
|
||||
return 'Client ID rejected';
|
||||
case MqttDisconnectReason.MQTT_SERVER_UNAVAILABLE:
|
||||
return 'Server unavailable';
|
||||
case MqttDisconnectReason.MQTT_MALFORMED_CREDENTIALS:
|
||||
return 'Malformed credentials';
|
||||
case MqttDisconnectReason.MQTT_NOT_AUTHORIZED:
|
||||
return 'Not authorized';
|
||||
case MqttDisconnectReason.TLS_BAD_FINGERPRINT:
|
||||
return 'TLS fingerprint invalid';
|
||||
default:
|
||||
return 'Unknown';
|
||||
}
|
||||
};
|
||||
|
||||
const content = () => {
|
||||
if (!data) {
|
||||
return <FormLoader onRetry={loadData} errorMessage={error?.message || ''} />;
|
||||
}
|
||||
|
||||
const renderConnectionStatus = () => (
|
||||
<>
|
||||
{!data.connected && (
|
||||
<>
|
||||
<ListItem>
|
||||
<ListItemAvatar>
|
||||
<Avatar>
|
||||
<ReportIcon />
|
||||
</Avatar>
|
||||
</ListItemAvatar>
|
||||
<ListItemText
|
||||
primary={LL.DISCONNECT_REASON()}
|
||||
secondary={disconnectReason(data)}
|
||||
/>
|
||||
</ListItem>
|
||||
<Divider variant="inset" component="li" />
|
||||
</>
|
||||
)}
|
||||
<ListItem>
|
||||
<ListItemAvatar>
|
||||
<Avatar>#</Avatar>
|
||||
</ListItemAvatar>
|
||||
<ListItemText primary={LL.ID_OF(LL.CLIENT())} secondary={data.client_id} />
|
||||
</ListItem>
|
||||
<Divider variant="inset" component="li" />
|
||||
<ListItem>
|
||||
<ListItemAvatar>
|
||||
<Avatar sx={{ bgcolor: mqttQueueHighlight(data, theme) }}>
|
||||
<AutoAwesomeMotionIcon />
|
||||
</Avatar>
|
||||
</ListItemAvatar>
|
||||
<ListItemText primary={LL.MQTT_QUEUE()} secondary={data.mqtt_queued} />
|
||||
</ListItem>
|
||||
<Divider variant="inset" component="li" />
|
||||
<ListItem>
|
||||
<ListItemAvatar>
|
||||
<Avatar sx={{ bgcolor: mqttPublishHighlight(data, theme) }}>
|
||||
<SpeakerNotesOffIcon />
|
||||
</Avatar>
|
||||
</ListItemAvatar>
|
||||
<ListItemText primary={LL.ERRORS_OF('MQTT')} secondary={data.mqtt_fails} />
|
||||
</ListItem>
|
||||
<Divider variant="inset" component="li" />
|
||||
</>
|
||||
);
|
||||
const mqttStatusText = useMemo(() => {
|
||||
if (!data) return '';
|
||||
if (!data.enabled) return LL.NOT_ENABLED();
|
||||
return data.connected
|
||||
? `${LL.CONNECTED(0)} (${data.connect_count})`
|
||||
: `${LL.DISCONNECTED()} (${data.connect_count})`;
|
||||
}, [data, LL]);
|
||||
|
||||
if (!data) {
|
||||
return (
|
||||
<SectionContent>
|
||||
<FormLoader onRetry={loadData} errorMessage={errorMessage} />
|
||||
</SectionContent>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<SectionContent>
|
||||
<List>
|
||||
<ListItem>
|
||||
<ListItemAvatar>
|
||||
@@ -156,15 +155,13 @@ const MqttStatus = () => {
|
||||
<DeviceHubIcon />
|
||||
</Avatar>
|
||||
</ListItemAvatar>
|
||||
<ListItemText primary={LL.STATUS_OF('')} secondary={mqttStatus(data)} />
|
||||
<ListItemText primary={LL.STATUS_OF('')} secondary={mqttStatusText} />
|
||||
</ListItem>
|
||||
<Divider variant="inset" component="li" />
|
||||
{data.enabled && renderConnectionStatus()}
|
||||
{data.enabled && <ConnectionStatus data={data} theme={theme} />}
|
||||
</List>
|
||||
);
|
||||
};
|
||||
|
||||
return <SectionContent>{content()}</SectionContent>;
|
||||
</SectionContent>
|
||||
);
|
||||
};
|
||||
|
||||
export default MqttStatus;
|
||||
|
||||
Reference in New Issue
Block a user