mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-06 15:59:52 +03:00
Merge branch 'dev' of https://github.com/emsesp/EMS-ESP32 into dev
This commit is contained in:
@@ -3,4 +3,3 @@
|
|||||||
# Firmware Installation
|
# Firmware Installation
|
||||||
|
|
||||||
Follow the instructions in the [documentation](https://emsesp.github.io/docs) on how to install the firmware binaries in the Assets below.
|
Follow the instructions in the [documentation](https://emsesp.github.io/docs) on how to install the firmware binaries in the Assets below.
|
||||||
|
|
||||||
|
|||||||
@@ -5,4 +5,3 @@ This is a snapshot of the current "beta" development code and firmware binaries
|
|||||||
# Firmware Installation
|
# Firmware Installation
|
||||||
|
|
||||||
Follow the instructions in the [documentation](https://emsesp.github.io/docs) on how to install the firmware binaries in the Assets below.
|
Follow the instructions in the [documentation](https://emsesp.github.io/docs) on how to install the firmware binaries in the Assets below.
|
||||||
|
|
||||||
|
|||||||
1063
interface/package-lock.json
generated
1063
interface/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -8,8 +8,8 @@
|
|||||||
"@emotion/styled": "^11.9.3",
|
"@emotion/styled": "^11.9.3",
|
||||||
"@msgpack/msgpack": "^2.7.2",
|
"@msgpack/msgpack": "^2.7.2",
|
||||||
"@mui/icons-material": "^5.8.4",
|
"@mui/icons-material": "^5.8.4",
|
||||||
"@mui/material": "^5.9.0",
|
"@mui/material": "^5.9.1",
|
||||||
"@table-library/react-table-library": "4.0.9",
|
"@table-library/react-table-library": "4.0.10",
|
||||||
"@types/lodash": "^4.14.182",
|
"@types/lodash": "^4.14.182",
|
||||||
"@types/node": "^18.0.6",
|
"@types/node": "^18.0.6",
|
||||||
"@types/react": "^18.0.15",
|
"@types/react": "^18.0.15",
|
||||||
|
|||||||
@@ -1,8 +1,18 @@
|
|||||||
import { AxiosPromise } from 'axios';
|
|
||||||
import { FC } from 'react';
|
import { FC } from 'react';
|
||||||
|
import { AxiosPromise } from 'axios';
|
||||||
|
|
||||||
|
import { Typography, Button, Box } from '@mui/material';
|
||||||
|
|
||||||
import { FileUploadConfig } from '../../api/endpoints';
|
import { FileUploadConfig } from '../../api/endpoints';
|
||||||
import { MessageBox, SingleUpload, useFileUpload } from '../../components';
|
import { SingleUpload, useFileUpload } from '../../components';
|
||||||
|
|
||||||
|
import DownloadIcon from '@mui/icons-material/GetApp';
|
||||||
|
|
||||||
|
import { useSnackbar } from 'notistack';
|
||||||
|
|
||||||
|
import { extractErrorMessage } from '../../utils';
|
||||||
|
|
||||||
|
import * as EMSESP from '../../project/api';
|
||||||
|
|
||||||
interface UploadFileProps {
|
interface UploadFileProps {
|
||||||
uploadGeneralFile: (file: File, config?: FileUploadConfig) => AxiosPromise<void>;
|
uploadGeneralFile: (file: File, config?: FileUploadConfig) => AxiosPromise<void>;
|
||||||
@@ -11,16 +21,93 @@ interface UploadFileProps {
|
|||||||
const GeneralFileUpload: FC<UploadFileProps> = ({ uploadGeneralFile }) => {
|
const GeneralFileUpload: FC<UploadFileProps> = ({ uploadGeneralFile }) => {
|
||||||
const [uploadFile, cancelUpload, uploading, uploadProgress] = useFileUpload({ upload: uploadGeneralFile });
|
const [uploadFile, cancelUpload, uploading, uploadProgress] = useFileUpload({ upload: uploadGeneralFile });
|
||||||
|
|
||||||
|
const { enqueueSnackbar } = useSnackbar();
|
||||||
|
|
||||||
|
const saveFile = (json: any, endpoint: string) => {
|
||||||
|
const a = document.createElement('a');
|
||||||
|
const filename = 'emsesp_' + endpoint + '.json';
|
||||||
|
a.href = URL.createObjectURL(
|
||||||
|
new Blob([JSON.stringify(json, null, 2)], {
|
||||||
|
type: 'text/plain'
|
||||||
|
})
|
||||||
|
);
|
||||||
|
a.setAttribute('download', filename);
|
||||||
|
document.body.appendChild(a);
|
||||||
|
a.click();
|
||||||
|
document.body.removeChild(a);
|
||||||
|
enqueueSnackbar('File downloaded', { variant: 'info' });
|
||||||
|
};
|
||||||
|
|
||||||
|
const downloadSettings = async () => {
|
||||||
|
try {
|
||||||
|
const response = await EMSESP.getSettings();
|
||||||
|
if (response.status !== 200) {
|
||||||
|
enqueueSnackbar('Unable to get settings', { variant: 'error' });
|
||||||
|
} else {
|
||||||
|
saveFile(response.data, 'settings');
|
||||||
|
}
|
||||||
|
} catch (error: unknown) {
|
||||||
|
enqueueSnackbar(extractErrorMessage(error, 'Problem with downloading'), { variant: 'error' });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const downloadCustomizations = async () => {
|
||||||
|
try {
|
||||||
|
const response = await EMSESP.getCustomizations();
|
||||||
|
if (response.status !== 200) {
|
||||||
|
enqueueSnackbar('Unable to get customizations', { variant: 'error' });
|
||||||
|
} else {
|
||||||
|
saveFile(response.data, 'customizations');
|
||||||
|
}
|
||||||
|
} catch (error: unknown) {
|
||||||
|
enqueueSnackbar(extractErrorMessage(error, 'Problem with downloading'), { variant: 'error' });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<Typography sx={{ pt: 2, pb: 2 }} variant="h6" color="primary">
|
||||||
|
Upload
|
||||||
|
</Typography>
|
||||||
{!uploading && (
|
{!uploading && (
|
||||||
<MessageBox
|
<Box mb={2} color="warning.main">
|
||||||
message="Upload a new firmware (.bin) file or an exported settings or customizations (.json) file below. EMS-ESP will restart afterwards to apply the new changes."
|
<Typography variant="body2">
|
||||||
level="warning"
|
Upload a new firmware (.bin) file, settings or customizations (.json) file below.
|
||||||
my={2}
|
</Typography>
|
||||||
/>
|
</Box>
|
||||||
)}
|
)}
|
||||||
<SingleUpload onDrop={uploadFile} onCancel={cancelUpload} uploading={uploading} progress={uploadProgress} />
|
<SingleUpload onDrop={uploadFile} onCancel={cancelUpload} uploading={uploading} progress={uploadProgress} />
|
||||||
|
|
||||||
|
<Typography sx={{ pt: 2, pb: 2 }} variant="h6" color="primary">
|
||||||
|
Download
|
||||||
|
</Typography>
|
||||||
|
{!uploading && (
|
||||||
|
<>
|
||||||
|
<Box color="warning.main">
|
||||||
|
<Typography mb={1} variant="body2">
|
||||||
|
Download the application settings. Be careful when sharing your settings as this file contains passwords
|
||||||
|
and other sensitive system information.
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
<Button startIcon={<DownloadIcon />} variant="outlined" color="primary" onClick={() => downloadSettings()}>
|
||||||
|
settings
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Box color="warning.main">
|
||||||
|
<Typography mt={2} mb={1} variant="body2">
|
||||||
|
Download the entity customizations.
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
<Button
|
||||||
|
startIcon={<DownloadIcon />}
|
||||||
|
variant="outlined"
|
||||||
|
color="primary"
|
||||||
|
onClick={() => downloadCustomizations()}
|
||||||
|
>
|
||||||
|
customizations
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ const System: FC = () => {
|
|||||||
<Tab value="log" label="System Log" />
|
<Tab value="log" label="System Log" />
|
||||||
|
|
||||||
{features.ota && <Tab value="ota" label="OTA Settings" disabled={!me.admin} />}
|
{features.ota && <Tab value="ota" label="OTA Settings" disabled={!me.admin} />}
|
||||||
{features.upload_firmware && <Tab value="upload" label="Upload" disabled={!me.admin} />}
|
{features.upload_firmware && <Tab value="upload" label="Upload/Download" disabled={!me.admin} />}
|
||||||
</RouterTabs>
|
</RouterTabs>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="status" element={<SystemStatusForm />} />
|
<Route path="status" element={<SystemStatusForm />} />
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ const UploadFileForm: FC = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SectionContent title="Upload File" titleGutter>
|
<SectionContent title="Upload/Download" titleGutter>
|
||||||
{restarting ? <RestartMonitor /> : <GeneralFileUpload uploadGeneralFile={uploadFile.current} />}
|
{restarting ? <RestartMonitor /> : <GeneralFileUpload uploadGeneralFile={uploadFile.current} />}
|
||||||
</SectionContent>
|
</SectionContent>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
import { FC, useContext } from 'react';
|
import { FC } from 'react';
|
||||||
|
|
||||||
import { Typography, Button, Box, List, ListItem, ListItemText, Link, ListItemAvatar } from '@mui/material';
|
import { Typography, Button, Box, List, ListItem, ListItemText, Link, ListItemAvatar } from '@mui/material';
|
||||||
|
|
||||||
import { SectionContent, ButtonRow, MessageBox } from '../components';
|
import { SectionContent } from '../components';
|
||||||
|
|
||||||
import { AuthenticatedContext } from '../contexts/authentication';
|
|
||||||
|
|
||||||
import { useSnackbar } from 'notistack';
|
import { useSnackbar } from 'notistack';
|
||||||
|
|
||||||
@@ -13,7 +11,6 @@ import MenuBookIcon from '@mui/icons-material/MenuBookTwoTone';
|
|||||||
import GitHubIcon from '@mui/icons-material/GitHub';
|
import GitHubIcon from '@mui/icons-material/GitHub';
|
||||||
import StarIcon from '@mui/icons-material/Star';
|
import StarIcon from '@mui/icons-material/Star';
|
||||||
import DownloadIcon from '@mui/icons-material/GetApp';
|
import DownloadIcon from '@mui/icons-material/GetApp';
|
||||||
import TuneIcon from '@mui/icons-material/Tune';
|
|
||||||
|
|
||||||
import { extractErrorMessage } from '../utils';
|
import { extractErrorMessage } from '../utils';
|
||||||
|
|
||||||
@@ -22,11 +19,9 @@ import * as EMSESP from './api';
|
|||||||
const HelpInformation: FC = () => {
|
const HelpInformation: FC = () => {
|
||||||
const { enqueueSnackbar } = useSnackbar();
|
const { enqueueSnackbar } = useSnackbar();
|
||||||
|
|
||||||
const { me } = useContext(AuthenticatedContext);
|
|
||||||
|
|
||||||
const saveFile = (json: any, endpoint: string) => {
|
const saveFile = (json: any, endpoint: string) => {
|
||||||
const a = document.createElement('a');
|
const a = document.createElement('a');
|
||||||
const filename = 'emsesp_' + endpoint;
|
const filename = 'emsesp_' + endpoint + '.txt';
|
||||||
a.href = URL.createObjectURL(
|
a.href = URL.createObjectURL(
|
||||||
new Blob([JSON.stringify(json, null, 2)], {
|
new Blob([JSON.stringify(json, null, 2)], {
|
||||||
type: 'text/plain'
|
type: 'text/plain'
|
||||||
@@ -36,7 +31,7 @@ const HelpInformation: FC = () => {
|
|||||||
document.body.appendChild(a);
|
document.body.appendChild(a);
|
||||||
a.click();
|
a.click();
|
||||||
document.body.removeChild(a);
|
document.body.removeChild(a);
|
||||||
enqueueSnackbar('File downloaded', { variant: 'info' });
|
enqueueSnackbar('System information downloaded', { variant: 'info' });
|
||||||
};
|
};
|
||||||
|
|
||||||
const callAPI = async (endpoint: string) => {
|
const callAPI = async (endpoint: string) => {
|
||||||
@@ -49,33 +44,7 @@ const HelpInformation: FC = () => {
|
|||||||
if (response.status !== 200) {
|
if (response.status !== 200) {
|
||||||
enqueueSnackbar('API call failed', { variant: 'error' });
|
enqueueSnackbar('API call failed', { variant: 'error' });
|
||||||
} else {
|
} else {
|
||||||
saveFile(response.data, endpoint + '.json.txt');
|
saveFile(response.data, endpoint);
|
||||||
}
|
|
||||||
} catch (error: unknown) {
|
|
||||||
enqueueSnackbar(extractErrorMessage(error, 'Problem with downloading'), { variant: 'error' });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const downloadSettings = async () => {
|
|
||||||
try {
|
|
||||||
const response = await EMSESP.getSettings();
|
|
||||||
if (response.status !== 200) {
|
|
||||||
enqueueSnackbar('Unable to get settings', { variant: 'error' });
|
|
||||||
} else {
|
|
||||||
saveFile(response.data, 'settings.json');
|
|
||||||
}
|
|
||||||
} catch (error: unknown) {
|
|
||||||
enqueueSnackbar(extractErrorMessage(error, 'Problem with downloading'), { variant: 'error' });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const downloadCustomizations = async () => {
|
|
||||||
try {
|
|
||||||
const response = await EMSESP.getCustomizations();
|
|
||||||
if (response.status !== 200) {
|
|
||||||
enqueueSnackbar('Unable to get customizations', { variant: 'error' });
|
|
||||||
} else {
|
|
||||||
saveFile(response.data, 'customizations.json');
|
|
||||||
}
|
}
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
enqueueSnackbar(extractErrorMessage(error, 'Problem with downloading'), { variant: 'error' });
|
enqueueSnackbar(extractErrorMessage(error, 'Problem with downloading'), { variant: 'error' });
|
||||||
@@ -83,33 +52,26 @@ const HelpInformation: FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SectionContent title="Application Information & Support" titleGutter>
|
<SectionContent title="Support Information" titleGutter>
|
||||||
<List>
|
<List>
|
||||||
<ListItem>
|
|
||||||
<ListItemAvatar>
|
|
||||||
<TuneIcon />
|
|
||||||
</ListItemAvatar>
|
|
||||||
<ListItemText>
|
|
||||||
For a help on each of the Application Settings see
|
|
||||||
<Link
|
|
||||||
target="_blank"
|
|
||||||
href="https://emsesp.github.io/docs/#/Configure-firmware?id=ems-esp-settings"
|
|
||||||
color="primary"
|
|
||||||
>
|
|
||||||
{'Configuring EMS-ESP'}
|
|
||||||
</Link>
|
|
||||||
</ListItemText>
|
|
||||||
</ListItem>
|
|
||||||
|
|
||||||
<ListItem>
|
<ListItem>
|
||||||
<ListItemAvatar>
|
<ListItemAvatar>
|
||||||
<MenuBookIcon />
|
<MenuBookIcon />
|
||||||
</ListItemAvatar>
|
</ListItemAvatar>
|
||||||
<ListItemText>
|
<ListItemText>
|
||||||
For general information about EMS-ESP visit the online
|
Visit the online
|
||||||
<Link target="_blank" href="https://emsesp.github.io/docs" color="primary">
|
<Link target="_blank" href="https://emsesp.github.io/docs" color="primary">
|
||||||
{'Documentation'}
|
{'Wiki'}
|
||||||
</Link>
|
</Link>
|
||||||
|
to get instructions on how to
|
||||||
|
<Link
|
||||||
|
target="_blank"
|
||||||
|
href="https://emsesp.github.io/docs/#/Configure-firmware?id=ems-esp-settings"
|
||||||
|
color="primary"
|
||||||
|
>
|
||||||
|
{'configure'}
|
||||||
|
</Link>
|
||||||
|
EMS-ESP and access other information.
|
||||||
</ListItemText>
|
</ListItemText>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
|
|
||||||
@@ -122,7 +84,7 @@ const HelpInformation: FC = () => {
|
|||||||
<Link target="_blank" href="https://discord.gg/3J3GgnzpyT" color="primary">
|
<Link target="_blank" href="https://discord.gg/3J3GgnzpyT" color="primary">
|
||||||
{'Discord'}
|
{'Discord'}
|
||||||
</Link>
|
</Link>
|
||||||
server
|
server.
|
||||||
</ListItemText>
|
</ListItemText>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
|
|
||||||
@@ -130,74 +92,33 @@ const HelpInformation: FC = () => {
|
|||||||
<ListItemAvatar>
|
<ListItemAvatar>
|
||||||
<GitHubIcon />
|
<GitHubIcon />
|
||||||
</ListItemAvatar>
|
</ListItemAvatar>
|
||||||
|
|
||||||
<ListItemText>
|
<ListItemText>
|
||||||
To report an issue or request a feature, please
|
Submit a
|
||||||
<Button
|
|
||||||
startIcon={<DownloadIcon />}
|
|
||||||
variant="outlined"
|
|
||||||
color="primary"
|
|
||||||
onClick={() => callAPI('info')}
|
|
||||||
>
|
|
||||||
download the debug information
|
|
||||||
</Button>
|
|
||||||
and include in a new
|
|
||||||
<Link target="_blank" href="https://github.com/emsesp/EMS-ESP32/issues/new/choose" color="primary">
|
<Link target="_blank" href="https://github.com/emsesp/EMS-ESP32/issues/new/choose" color="primary">
|
||||||
GitHub issue
|
support issue
|
||||||
</Link>
|
</Link>
|
||||||
|
for requesting a new feature or reporting a bug.
|
||||||
|
<br />
|
||||||
|
Make sure you also
|
||||||
|
<Button startIcon={<DownloadIcon />} variant="outlined" color="primary" onClick={() => callAPI('info')}>
|
||||||
|
download
|
||||||
|
</Button>
|
||||||
|
and attach your system details for a faster response.
|
||||||
</ListItemText>
|
</ListItemText>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
</List>
|
</List>
|
||||||
|
|
||||||
{me.admin && (
|
<Box border={1} p={1} mt={4}>
|
||||||
<>
|
<Typography align="center" variant="h6" color="orange">
|
||||||
<Typography sx={{ pt: 2, pb: 2 }} variant="h6" color="primary">
|
EMS-ESP will always be a free and open-source project
|
||||||
Download Settings
|
<br></br>Please consider supporting it with a
|
||||||
</Typography>
|
<StarIcon style={{ fontSize: 16, color: 'yellow', verticalAlign: 'middle' }} /> on
|
||||||
<Box color="warning.main">
|
|
||||||
<Typography variant="body2">
|
|
||||||
Export the application settings and any customizations to a JSON file. These files can later be uploaded
|
|
||||||
via System→Upload.
|
|
||||||
</Typography>
|
|
||||||
</Box>
|
|
||||||
<Box sx={{ display: 'flex' }}>
|
|
||||||
<ButtonRow>
|
|
||||||
<Button
|
|
||||||
startIcon={<DownloadIcon />}
|
|
||||||
variant="outlined"
|
|
||||||
color="primary"
|
|
||||||
onClick={() => downloadSettings()}
|
|
||||||
>
|
|
||||||
settings
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
startIcon={<DownloadIcon />}
|
|
||||||
variant="outlined"
|
|
||||||
color="primary"
|
|
||||||
onClick={() => downloadCustomizations()}
|
|
||||||
>
|
|
||||||
customizations
|
|
||||||
</Button>
|
|
||||||
</ButtonRow>
|
|
||||||
</Box>
|
|
||||||
<MessageBox
|
|
||||||
my={2}
|
|
||||||
level="warning"
|
|
||||||
message="Be careful when sharing your Settings as the file contains passwords and other sensitive system
|
|
||||||
information!"
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<Box bgcolor="secondary.info" border={1} p={1} mt={4}>
|
|
||||||
<Typography align="center" variant="h6">
|
|
||||||
EMS-ESP is a free and open-source project.
|
|
||||||
<br></br>Please consider supporting us by giving it a
|
|
||||||
<StarIcon style={{ fontSize: 16, color: '#fdff3a', verticalAlign: 'middle' }} /> on
|
|
||||||
<Link href="https://github.com/emsesp/EMS-ESP32" color="primary">
|
<Link href="https://github.com/emsesp/EMS-ESP32" color="primary">
|
||||||
{'GitHub'}
|
{'GitHub'}
|
||||||
</Link>
|
</Link>
|
||||||
!
|
|
||||||
</Typography>
|
</Typography>
|
||||||
|
<Typography align="center">@proddy @MichaelDvP</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
</SectionContent>
|
</SectionContent>
|
||||||
);
|
);
|
||||||
|
|||||||
1534
mock-api/package-lock.json
generated
1534
mock-api/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -15,7 +15,7 @@
|
|||||||
"compression": "^1.7.4",
|
"compression": "^1.7.4",
|
||||||
"express": "^4.18.1",
|
"express": "^4.18.1",
|
||||||
"express-sse": "^0.5.3",
|
"express-sse": "^0.5.3",
|
||||||
"nodemon": "^2.0.18",
|
"nodemon": "^2.0.19",
|
||||||
"ws": "^8.8.0"
|
"ws": "^8.8.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
34
src/mqtt.cpp
34
src/mqtt.cpp
@@ -445,19 +445,17 @@ void Mqtt::start() {
|
|||||||
}
|
}
|
||||||
connecting_ = false;
|
connecting_ = false;
|
||||||
if (reason == AsyncMqttClientDisconnectReason::TCP_DISCONNECTED) {
|
if (reason == AsyncMqttClientDisconnectReason::TCP_DISCONNECTED) {
|
||||||
LOG_INFO(F("MQTT disconnected: TCP"));
|
LOG_WARNING(F("MQTT disconnected: TCP"));
|
||||||
}
|
} else if (reason == AsyncMqttClientDisconnectReason::MQTT_IDENTIFIER_REJECTED) {
|
||||||
if (reason == AsyncMqttClientDisconnectReason::MQTT_IDENTIFIER_REJECTED) {
|
LOG_WARNING(F("MQTT disconnected: Identifier Rejected"));
|
||||||
LOG_INFO(F("MQTT disconnected: Identifier Rejected"));
|
} else if (reason == AsyncMqttClientDisconnectReason::MQTT_SERVER_UNAVAILABLE) {
|
||||||
}
|
LOG_WARNING(F("MQTT disconnected: Server unavailable"));
|
||||||
if (reason == AsyncMqttClientDisconnectReason::MQTT_SERVER_UNAVAILABLE) {
|
} else if (reason == AsyncMqttClientDisconnectReason::MQTT_MALFORMED_CREDENTIALS) {
|
||||||
LOG_INFO(F("MQTT disconnected: Server unavailable"));
|
LOG_WARNING(F("MQTT disconnected: Malformed credentials"));
|
||||||
}
|
} else if (reason == AsyncMqttClientDisconnectReason::MQTT_NOT_AUTHORIZED) {
|
||||||
if (reason == AsyncMqttClientDisconnectReason::MQTT_MALFORMED_CREDENTIALS) {
|
LOG_WARNING(F("MQTT disconnected: Not authorized"));
|
||||||
LOG_INFO(F("MQTT disconnected: Malformed credentials"));
|
} else {
|
||||||
}
|
LOG_WARNING(F("MQTT disconnected: code %d"), reason);
|
||||||
if (reason == AsyncMqttClientDisconnectReason::MQTT_NOT_AUTHORIZED) {
|
|
||||||
LOG_INFO(F("MQTT disconnected: Not authorized"));
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -628,11 +626,11 @@ void Mqtt::ha_status() {
|
|||||||
doc["~"] = mqtt_base_; // default ems-esp
|
doc["~"] = mqtt_base_; // default ems-esp
|
||||||
// doc["avty_t"] = FJSON("~/status"); // commented out, as it causes errors in HA sometimes
|
// doc["avty_t"] = FJSON("~/status"); // commented out, as it causes errors in HA sometimes
|
||||||
// doc["json_attr_t"] = FJSON("~/heartbeat"); // store also as HA attributes
|
// doc["json_attr_t"] = FJSON("~/heartbeat"); // store also as HA attributes
|
||||||
doc["stat_t"] = FJSON("~/heartbeat");
|
doc["stat_t"] = FJSON("~/heartbeat");
|
||||||
doc["object_id"] = FJSON("ems_esp_status");
|
doc["object_id"] = FJSON("ems_esp_status");
|
||||||
doc["name"] = FJSON("EMS-ESP status");
|
doc["name"] = FJSON("EMS-ESP status");
|
||||||
doc["ic"] = F_(icondevice);
|
doc["ic"] = F_(icondevice);
|
||||||
doc["val_tpl"] = FJSON("{{value_json['bus_status']}}");
|
doc["val_tpl"] = FJSON("{{value_json['bus_status']}}");
|
||||||
|
|
||||||
JsonObject dev = doc.createNestedObject("dev");
|
JsonObject dev = doc.createNestedObject("dev");
|
||||||
dev["name"] = F_(EMSESP); // "EMS-ESP"
|
dev["name"] = F_(EMSESP); // "EMS-ESP"
|
||||||
@@ -1121,7 +1119,7 @@ void Mqtt::publish_ha_sensor_config(uint8_t type,
|
|||||||
|
|
||||||
// name (friendly name) = <tag> <name>
|
// name (friendly name) = <tag> <name>
|
||||||
short_name[0] = toupper(short_name[0]); // capitalize first letter
|
short_name[0] = toupper(short_name[0]); // capitalize first letter
|
||||||
doc["name"] = short_name;
|
doc["name"] = short_name;
|
||||||
|
|
||||||
// value template
|
// value template
|
||||||
// if its nested mqtt format then use the appended entity name, otherwise take the original
|
// if its nested mqtt format then use the appended entity name, otherwise take the original
|
||||||
|
|||||||
@@ -57,7 +57,6 @@ void Shower::loop() {
|
|||||||
// first check to see if hot water has been on long enough to be recognized as a Shower/Bath
|
// first check to see if hot water has been on long enough to be recognized as a Shower/Bath
|
||||||
if (!shower_state_ && (time_now - timer_start_) > SHOWER_MIN_DURATION) {
|
if (!shower_state_ && (time_now - timer_start_) > SHOWER_MIN_DURATION) {
|
||||||
set_shower_state(true);
|
set_shower_state(true);
|
||||||
publish_shower_data();
|
|
||||||
LOG_DEBUG(F("[Shower] hot water still running, starting shower timer"));
|
LOG_DEBUG(F("[Shower] hot water still running, starting shower timer"));
|
||||||
}
|
}
|
||||||
// check if the shower has been on too long
|
// check if the shower has been on too long
|
||||||
@@ -78,7 +77,12 @@ void Shower::loop() {
|
|||||||
if ((timer_pause_ - timer_start_) > SHOWER_OFFSET_TIME) {
|
if ((timer_pause_ - timer_start_) > SHOWER_OFFSET_TIME) {
|
||||||
duration_ = (timer_pause_ - timer_start_ - SHOWER_OFFSET_TIME);
|
duration_ = (timer_pause_ - timer_start_ - SHOWER_OFFSET_TIME);
|
||||||
if (duration_ > SHOWER_MIN_DURATION) {
|
if (duration_ > SHOWER_MIN_DURATION) {
|
||||||
publish_shower_data();
|
StaticJsonDocument<EMSESP_JSON_SIZE_SMALL> doc;
|
||||||
|
|
||||||
|
char s[50];
|
||||||
|
snprintf(s, 50, "%d minutes and %d seconds", (uint8_t)(duration_ / 60000), (uint8_t)((duration_ / 1000) % 60));
|
||||||
|
doc["duration"] = s;
|
||||||
|
Mqtt::publish(F("shower_data"), doc.as<JsonObject>());
|
||||||
LOG_DEBUG(F("[Shower] finished with duration %d"), duration_);
|
LOG_DEBUG(F("[Shower] finished with duration %d"), duration_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -120,34 +124,6 @@ void Shower::shower_alert_start() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Publish to the shower_data topic
|
|
||||||
// showing whether the shower timer and alert are enabled or disabled
|
|
||||||
// and the duration of the last shower
|
|
||||||
void Shower::publish_shower_data() const {
|
|
||||||
StaticJsonDocument<EMSESP_JSON_SIZE_SMALL> doc;
|
|
||||||
|
|
||||||
if (EMSESP::system_.bool_format() == BOOL_FORMAT_TRUEFALSE) {
|
|
||||||
doc["shower_timer"] = shower_timer_;
|
|
||||||
doc["shower_alert"] = shower_alert_;
|
|
||||||
} else if (EMSESP::system_.bool_format() == BOOL_FORMAT_10) {
|
|
||||||
doc["shower_timer"] = shower_timer_ ? 1 : 0;
|
|
||||||
doc["shower_alert"] = shower_alert_ ? 1 : 0;
|
|
||||||
} else {
|
|
||||||
char result[10];
|
|
||||||
doc["shower_timer"] = Helpers::render_boolean(result, shower_timer_);
|
|
||||||
doc["shower_alert"] = Helpers::render_boolean(result, shower_alert_);
|
|
||||||
}
|
|
||||||
|
|
||||||
// only publish shower duration if there is a value
|
|
||||||
if (duration_ > SHOWER_MIN_DURATION) {
|
|
||||||
char s[50];
|
|
||||||
snprintf(s, 50, "%d minutes and %d seconds", (uint8_t)(duration_ / 60000), (uint8_t)((duration_ / 1000) % 60));
|
|
||||||
doc["duration"] = s;
|
|
||||||
}
|
|
||||||
|
|
||||||
Mqtt::publish(F("shower_data"), doc.as<JsonObject>());
|
|
||||||
}
|
|
||||||
|
|
||||||
// send status of shower to MQTT topic called shower_active - which is determined by the state parameter
|
// send status of shower to MQTT topic called shower_active - which is determined by the state parameter
|
||||||
// and creates the HA config topic if HA enabled
|
// and creates the HA config topic if HA enabled
|
||||||
// force is used by EMSESP::publish_all_loop()
|
// force is used by EMSESP::publish_all_loop()
|
||||||
|
|||||||
20
src/shower.h
20
src/shower.h
@@ -30,25 +30,6 @@ class Shower {
|
|||||||
|
|
||||||
void set_shower_state(bool state, bool force = false);
|
void set_shower_state(bool state, bool force = false);
|
||||||
|
|
||||||
/* unused header
|
|
||||||
*
|
|
||||||
bool shower_alert() const {
|
|
||||||
return shower_alert_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void shower_alert(const bool shower_alert) {
|
|
||||||
shower_alert_ = shower_alert;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool shower_timer() const {
|
|
||||||
return shower_timer_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void shower_timer(const bool shower_timer) {
|
|
||||||
shower_timer_ = shower_timer;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static uuid::log::Logger logger_;
|
static uuid::log::Logger logger_;
|
||||||
|
|
||||||
@@ -56,7 +37,6 @@ class Shower {
|
|||||||
static constexpr uint32_t SHOWER_MIN_DURATION = 120000; // in ms. 2 minutes, before recognizing its a shower
|
static constexpr uint32_t SHOWER_MIN_DURATION = 120000; // in ms. 2 minutes, before recognizing its a shower
|
||||||
static constexpr uint32_t SHOWER_OFFSET_TIME = 5000; // in ms. 5 seconds grace time, to calibrate actual time under the shower
|
static constexpr uint32_t SHOWER_OFFSET_TIME = 5000; // in ms. 5 seconds grace time, to calibrate actual time under the shower
|
||||||
|
|
||||||
void publish_shower_data() const;
|
|
||||||
void shower_alert_start();
|
void shower_alert_start();
|
||||||
void shower_alert_stop();
|
void shower_alert_stop();
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
#define EMSESP_APP_VERSION "3.4.2b3"
|
#define EMSESP_APP_VERSION "3.4.2b4"
|
||||||
|
|||||||
Reference in New Issue
Block a user