mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-06 15:59:52 +03:00
add optional secure mqtt
This commit is contained in:
@@ -1,12 +1,17 @@
|
|||||||
import CancelIcon from '@mui/icons-material/Cancel';
|
import CancelIcon from '@mui/icons-material/Cancel';
|
||||||
import WarningIcon from '@mui/icons-material/Warning';
|
import WarningIcon from '@mui/icons-material/Warning';
|
||||||
|
import PowerSettingsNewIcon from '@mui/icons-material/PowerSettingsNew';
|
||||||
import { Button, Checkbox, MenuItem, Grid, Typography, InputAdornment, TextField } from '@mui/material';
|
import { Button, Checkbox, MenuItem, Grid, Typography, InputAdornment, TextField } from '@mui/material';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import type { ValidateFieldsError } from 'async-validator';
|
import type { ValidateFieldsError } from 'async-validator';
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
|
import { toast } from 'react-toastify';
|
||||||
|
import RestartMonitor from '../system/RestartMonitor';
|
||||||
|
import { useRequest } from 'alova';
|
||||||
|
|
||||||
import type { MqttSettings } from 'types';
|
import type { MqttSettings } from 'types';
|
||||||
import * as MqttApi from 'api/mqtt';
|
import * as MqttApi from 'api/mqtt';
|
||||||
|
import * as SystemApi from 'api/system';
|
||||||
import {
|
import {
|
||||||
BlockFormControlLabel,
|
BlockFormControlLabel,
|
||||||
ButtonRow,
|
ButtonRow,
|
||||||
@@ -14,6 +19,7 @@ import {
|
|||||||
SectionContent,
|
SectionContent,
|
||||||
ValidatedPasswordField,
|
ValidatedPasswordField,
|
||||||
ValidatedTextField,
|
ValidatedTextField,
|
||||||
|
MessageBox,
|
||||||
BlockNavigation
|
BlockNavigation
|
||||||
} from 'components';
|
} from 'components';
|
||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
@@ -32,15 +38,21 @@ const MqttSettingsForm: FC = () => {
|
|||||||
setDirtyFlags,
|
setDirtyFlags,
|
||||||
blocker,
|
blocker,
|
||||||
saveData,
|
saveData,
|
||||||
errorMessage
|
errorMessage,
|
||||||
|
restartNeeded
|
||||||
} = useRest<MqttSettings>({
|
} = useRest<MqttSettings>({
|
||||||
read: MqttApi.readMqttSettings,
|
read: MqttApi.readMqttSettings,
|
||||||
update: MqttApi.updateMqttSettings
|
update: MqttApi.updateMqttSettings
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { send: restartCommand } = useRequest(SystemApi.restart(), {
|
||||||
|
immediate: false
|
||||||
|
});
|
||||||
|
|
||||||
const { LL } = useI18nContext();
|
const { LL } = useI18nContext();
|
||||||
|
|
||||||
const [fieldErrors, setFieldErrors] = useState<ValidateFieldsError>();
|
const [fieldErrors, setFieldErrors] = useState<ValidateFieldsError>();
|
||||||
|
const [restarting, setRestarting] = useState(false);
|
||||||
|
|
||||||
const updateFormValue = updateValueDirty(origData, dirtyFlags, setDirtyFlags, updateDataValue);
|
const updateFormValue = updateValueDirty(origData, dirtyFlags, setDirtyFlags, updateDataValue);
|
||||||
|
|
||||||
@@ -59,6 +71,13 @@ const MqttSettingsForm: FC = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const restart = async () => {
|
||||||
|
await restartCommand().catch((error) => {
|
||||||
|
toast.error(error.message);
|
||||||
|
});
|
||||||
|
setRestarting(true);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<BlockFormControlLabel
|
<BlockFormControlLabel
|
||||||
@@ -168,6 +187,17 @@ const MqttSettingsForm: FC = () => {
|
|||||||
<MenuItem value={2}>2</MenuItem>
|
<MenuItem value={2}>2</MenuItem>
|
||||||
</TextField>
|
</TextField>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
<Grid item xs={12} sm={6}>
|
||||||
|
<ValidatedPasswordField
|
||||||
|
name="rootCA"
|
||||||
|
label={LL.CERT()}
|
||||||
|
fullWidth
|
||||||
|
variant="outlined"
|
||||||
|
value={data.rootCA}
|
||||||
|
onChange={updateFormValue}
|
||||||
|
margin="normal"
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
<BlockFormControlLabel
|
<BlockFormControlLabel
|
||||||
control={<Checkbox name="clean_session" checked={data.clean_session} onChange={updateFormValue} />}
|
control={<Checkbox name="clean_session" checked={data.clean_session} onChange={updateFormValue} />}
|
||||||
@@ -400,7 +430,15 @@ const MqttSettingsForm: FC = () => {
|
|||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
{dirtyFlags && dirtyFlags.length !== 0 && (
|
{restartNeeded && (
|
||||||
|
<MessageBox my={2} level="warning" message={LL.RESTART_TEXT()}>
|
||||||
|
<Button startIcon={<PowerSettingsNewIcon />} variant="contained" color="error" onClick={restart}>
|
||||||
|
{LL.RESTART()}
|
||||||
|
</Button>
|
||||||
|
</MessageBox>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!restartNeeded && dirtyFlags && dirtyFlags.length !== 0 && (
|
||||||
<ButtonRow>
|
<ButtonRow>
|
||||||
<Button
|
<Button
|
||||||
startIcon={<CancelIcon />}
|
startIcon={<CancelIcon />}
|
||||||
@@ -431,7 +469,7 @@ const MqttSettingsForm: FC = () => {
|
|||||||
return (
|
return (
|
||||||
<SectionContent title={LL.SETTINGS_OF('MQTT')} titleGutter>
|
<SectionContent title={LL.SETTINGS_OF('MQTT')} titleGutter>
|
||||||
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
||||||
{content()}
|
{restarting ? <RestartMonitor /> : content()}
|
||||||
</SectionContent>
|
</SectionContent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -45,9 +45,9 @@ const de: Translation = {
|
|||||||
CHANGE_VALUE: 'Wert ändern',
|
CHANGE_VALUE: 'Wert ändern',
|
||||||
CANCEL: 'Abbrechen',
|
CANCEL: 'Abbrechen',
|
||||||
RESET: 'Zurücksetzen',
|
RESET: 'Zurücksetzen',
|
||||||
APPLY_CHANGES: 'Apply Changes ({0})', // TODO translate
|
APPLY_CHANGES: 'Änderungen anwenden ({0})',
|
||||||
UPDATE: 'Update', // TODO translate
|
UPDATE: 'Update',
|
||||||
EXECUTE: 'Execute', // TODO translate
|
EXECUTE: 'Ausführen',
|
||||||
REMOVE: 'Entfernen',
|
REMOVE: 'Entfernen',
|
||||||
PROBLEM_UPDATING: 'Problem beim Aktualisieren',
|
PROBLEM_UPDATING: 'Problem beim Aktualisieren',
|
||||||
PROBLEM_LOADING: 'Problem beim Laden',
|
PROBLEM_LOADING: 'Problem beim Laden',
|
||||||
@@ -180,7 +180,7 @@ const de: Translation = {
|
|||||||
LOG_OF: '{0} Log',
|
LOG_OF: '{0} Log',
|
||||||
STATUS_OF: '{0} Status',
|
STATUS_OF: '{0} Status',
|
||||||
UPLOAD_DOWNLOAD: 'Hoch-/Herunterladen',
|
UPLOAD_DOWNLOAD: 'Hoch-/Herunterladen',
|
||||||
VERSION_ON: 'You are currently on', // TODO translate
|
VERSION_ON: 'Sie verwenden derzeit',
|
||||||
SYSTEM_APPLY_FIRMWARE: 'um die neue Firmware anzuwenden',
|
SYSTEM_APPLY_FIRMWARE: 'um die neue Firmware anzuwenden',
|
||||||
CLOSE: 'Schließen',
|
CLOSE: 'Schließen',
|
||||||
USE: 'Verwenden Sie',
|
USE: 'Verwenden Sie',
|
||||||
@@ -240,7 +240,7 @@ const de: Translation = {
|
|||||||
MQTT_PUBLISH_TEXT_2: 'Veröffentliche als Kommando-Topic (ioBroker)',
|
MQTT_PUBLISH_TEXT_2: 'Veröffentliche als Kommando-Topic (ioBroker)',
|
||||||
MQTT_PUBLISH_TEXT_3: 'Aktiviere `MQTT Discovery`',
|
MQTT_PUBLISH_TEXT_3: 'Aktiviere `MQTT Discovery`',
|
||||||
MQTT_PUBLISH_TEXT_4: 'Prefix für die `Discovery`-Topics',
|
MQTT_PUBLISH_TEXT_4: 'Prefix für die `Discovery`-Topics',
|
||||||
MQTT_PUBLISH_TEXT_5: 'Discovery type', // TODO translate
|
MQTT_PUBLISH_TEXT_5: 'Discovery Typ',
|
||||||
MQTT_PUBLISH_INTERVALS: 'Veröffentlichungs-Intervalle',
|
MQTT_PUBLISH_INTERVALS: 'Veröffentlichungs-Intervalle',
|
||||||
MQTT_INT_BOILER: 'Boiler und Wärmepumpen',
|
MQTT_INT_BOILER: 'Boiler und Wärmepumpen',
|
||||||
MQTT_INT_THERMOSTATS: 'Thermostate',
|
MQTT_INT_THERMOSTATS: 'Thermostate',
|
||||||
@@ -282,7 +282,7 @@ const de: Translation = {
|
|||||||
SCAN_AGAIN: 'Erneute Suche',
|
SCAN_AGAIN: 'Erneute Suche',
|
||||||
NETWORK_SCANNER: 'Netzwerk Suche',
|
NETWORK_SCANNER: 'Netzwerk Suche',
|
||||||
NETWORK_NO_WIFI: 'Keine WiFi Netzwerke gefunden',
|
NETWORK_NO_WIFI: 'Keine WiFi Netzwerke gefunden',
|
||||||
NETWORK_BLANK_SSID: 'Freilassen um WiFi zu deaktivieren',
|
NETWORK_BLANK_SSID: 'Freilassen um WiFi zu deaktivieren und ETH zu aktivieren',
|
||||||
TX_POWER: 'Tx Leistung',
|
TX_POWER: 'Tx Leistung',
|
||||||
HOSTNAME: 'Hostname',
|
HOSTNAME: 'Hostname',
|
||||||
NETWORK_DISABLE_SLEEP: 'Deaktiviere WiFi Schlafmodus',
|
NETWORK_DISABLE_SLEEP: 'Deaktiviere WiFi Schlafmodus',
|
||||||
@@ -319,10 +319,11 @@ const de: Translation = {
|
|||||||
SCHEDULE_TIMER_3: 'jede Stunde',
|
SCHEDULE_TIMER_3: 'jede Stunde',
|
||||||
CUSTOM_ENTITIES: 'Individuelle Entitäten',
|
CUSTOM_ENTITIES: 'Individuelle Entitäten',
|
||||||
ENTITIES_HELP_1: 'Abfrage von Werten auf dem EMS-Bus',
|
ENTITIES_HELP_1: 'Abfrage von Werten auf dem EMS-Bus',
|
||||||
ENTITIES_UPDATED: 'Entities Updated', // TODO translate
|
ENTITIES_UPDATED: 'Entitäten gespeichert',
|
||||||
WRITEABLE: 'Schreibbar',
|
WRITEABLE: 'Schreibbar',
|
||||||
SHOWING: 'Showing', // TODO translate
|
SHOWING: 'Anzeigen von',
|
||||||
SEARCH: 'Search' // TODO translate
|
SEARCH: 'Suche',
|
||||||
|
CERT: 'TSL Zertifikat (Freilassen um TSL zu deaktivieren)'
|
||||||
};
|
};
|
||||||
|
|
||||||
export default de;
|
export default de;
|
||||||
|
|||||||
@@ -282,7 +282,7 @@ const en: Translation = {
|
|||||||
SCAN_AGAIN: 'Scan again',
|
SCAN_AGAIN: 'Scan again',
|
||||||
NETWORK_SCANNER: 'Network Scanner',
|
NETWORK_SCANNER: 'Network Scanner',
|
||||||
NETWORK_NO_WIFI: 'No WiFi networks found',
|
NETWORK_NO_WIFI: 'No WiFi networks found',
|
||||||
NETWORK_BLANK_SSID: 'leave blank to disable WiFi',
|
NETWORK_BLANK_SSID: 'leave blank to disable WiFi and enable ETH',
|
||||||
TX_POWER: 'Tx Power',
|
TX_POWER: 'Tx Power',
|
||||||
HOSTNAME: 'Hostname',
|
HOSTNAME: 'Hostname',
|
||||||
NETWORK_DISABLE_SLEEP: 'Disable WiFi Sleep Mode',
|
NETWORK_DISABLE_SLEEP: 'Disable WiFi Sleep Mode',
|
||||||
@@ -322,8 +322,8 @@ const en: Translation = {
|
|||||||
ENTITIES_UPDATED: 'Entities Updated',
|
ENTITIES_UPDATED: 'Entities Updated',
|
||||||
WRITEABLE: 'Writeable',
|
WRITEABLE: 'Writeable',
|
||||||
SHOWING: 'Showing',
|
SHOWING: 'Showing',
|
||||||
SEARCH: 'Search'
|
SEARCH: 'Search',
|
||||||
|
CERT: 'TSL root certificate (leave blank to disable TSL)'
|
||||||
};
|
};
|
||||||
|
|
||||||
export default en;
|
export default en;
|
||||||
|
|||||||
@@ -282,7 +282,7 @@ const fr: Translation = {
|
|||||||
SCAN_AGAIN: 'Rescanner',
|
SCAN_AGAIN: 'Rescanner',
|
||||||
NETWORK_SCANNER: 'Scan réseau',
|
NETWORK_SCANNER: 'Scan réseau',
|
||||||
NETWORK_NO_WIFI: 'Pas de réseau WiFi trouvé',
|
NETWORK_NO_WIFI: 'Pas de réseau WiFi trouvé',
|
||||||
NETWORK_BLANK_SSID: 'laisser vide pour désactiver le WiFi',
|
NETWORK_BLANK_SSID: 'laisser vide pour désactiver le WiFi', // and enable ETH // TODO translate
|
||||||
TX_POWER: 'Puissance Tx',
|
TX_POWER: 'Puissance Tx',
|
||||||
HOSTNAME: 'Nom d\'hôte',
|
HOSTNAME: 'Nom d\'hôte',
|
||||||
NETWORK_DISABLE_SLEEP: 'Désactiver le mode veille du WiFi',
|
NETWORK_DISABLE_SLEEP: 'Désactiver le mode veille du WiFi',
|
||||||
@@ -322,7 +322,8 @@ const fr: Translation = {
|
|||||||
ENTITIES_UPDATED: 'Entities Updated', // TODO translate
|
ENTITIES_UPDATED: 'Entities Updated', // TODO translate
|
||||||
WRITEABLE: 'Writeable', // TODO translate
|
WRITEABLE: 'Writeable', // TODO translate
|
||||||
SHOWING: 'Showing', // TODO translate
|
SHOWING: 'Showing', // TODO translate
|
||||||
SEARCH: 'Search' // TODO translate
|
SEARCH: 'Search', // TODO translate
|
||||||
|
CERT: 'TSL root certificate (leave blank to disable TSL)' // TODO translate
|
||||||
};
|
};
|
||||||
|
|
||||||
export default fr;
|
export default fr;
|
||||||
|
|||||||
@@ -324,8 +324,8 @@ const it: Translation = {
|
|||||||
ENTITIES_UPDATED: 'Entità aggiornate',
|
ENTITIES_UPDATED: 'Entità aggiornate',
|
||||||
WRITEABLE: 'Scrivibile',
|
WRITEABLE: 'Scrivibile',
|
||||||
SHOWING: 'Visualizza',
|
SHOWING: 'Visualizza',
|
||||||
SEARCH: 'Ricerca'
|
SEARCH: 'Ricerca',
|
||||||
|
CERT: 'TSL root certificate (leave blank to disable TSL)' // TODO translate
|
||||||
};
|
};
|
||||||
|
|
||||||
export default it;
|
export default it;
|
||||||
|
|||||||
@@ -282,7 +282,7 @@ const nl: Translation = {
|
|||||||
SCAN_AGAIN: 'Opnieuw scannen',
|
SCAN_AGAIN: 'Opnieuw scannen',
|
||||||
NETWORK_SCANNER: 'Netwerk Scanner',
|
NETWORK_SCANNER: 'Netwerk Scanner',
|
||||||
NETWORK_NO_WIFI: 'Geen WiFi networken gevonden',
|
NETWORK_NO_WIFI: 'Geen WiFi networken gevonden',
|
||||||
NETWORK_BLANK_SSID: 'laat leeg om WiFi uit te schakelen',
|
NETWORK_BLANK_SSID: 'laat leeg om WiFi uit te schakelen', // and enable ETH // TODO translate
|
||||||
TX_POWER: 'Tx Vermogen',
|
TX_POWER: 'Tx Vermogen',
|
||||||
HOSTNAME: 'Hostname',
|
HOSTNAME: 'Hostname',
|
||||||
NETWORK_DISABLE_SLEEP: 'WiFi Sleep Mode uitzetten',
|
NETWORK_DISABLE_SLEEP: 'WiFi Sleep Mode uitzetten',
|
||||||
@@ -322,7 +322,8 @@ const nl: Translation = {
|
|||||||
ENTITIES_UPDATED: 'Entiteiten bijgewerkt',
|
ENTITIES_UPDATED: 'Entiteiten bijgewerkt',
|
||||||
WRITEABLE: 'Beschrijfbare',
|
WRITEABLE: 'Beschrijfbare',
|
||||||
SHOWING: 'Tonen',
|
SHOWING: 'Tonen',
|
||||||
SEARCH: 'Zoek'
|
SEARCH: 'Zoek',
|
||||||
|
CERT: 'TSL root certificate (leave blank to disable TSL)' // TODO translate
|
||||||
};
|
};
|
||||||
|
|
||||||
export default nl;
|
export default nl;
|
||||||
|
|||||||
@@ -282,7 +282,7 @@ const no: Translation = {
|
|||||||
SCAN_AGAIN: 'Søk igjen',
|
SCAN_AGAIN: 'Søk igjen',
|
||||||
NETWORK_SCANNER: 'Nettverk Scanner',
|
NETWORK_SCANNER: 'Nettverk Scanner',
|
||||||
NETWORK_NO_WIFI: 'Ingen trådløse nett funnet',
|
NETWORK_NO_WIFI: 'Ingen trådløse nett funnet',
|
||||||
NETWORK_BLANK_SSID: 'la feltet være blankt for å deaktivisere trådløst nettverk',
|
NETWORK_BLANK_SSID: 'la feltet være blankt for å deaktivisere trådløst nettverk', // and enable ETH // TODO translate
|
||||||
TX_POWER: 'Tx Effekt',
|
TX_POWER: 'Tx Effekt',
|
||||||
HOSTNAME: 'Hostname',
|
HOSTNAME: 'Hostname',
|
||||||
NETWORK_DISABLE_SLEEP: 'Hindre at trådløst nettverk går i Sleep Mode',
|
NETWORK_DISABLE_SLEEP: 'Hindre at trådløst nettverk går i Sleep Mode',
|
||||||
@@ -322,8 +322,8 @@ const no: Translation = {
|
|||||||
ENTITIES_UPDATED: 'Entities Updated', // TODO translate
|
ENTITIES_UPDATED: 'Entities Updated', // TODO translate
|
||||||
WRITEABLE: 'Writeable', // TODO translate
|
WRITEABLE: 'Writeable', // TODO translate
|
||||||
SHOWING: 'Showing', // TODO translate
|
SHOWING: 'Showing', // TODO translate
|
||||||
SEARCH: 'Search' // TODO translate
|
SEARCH: 'Search', // TODO translate
|
||||||
|
CERT: 'TSL root certificate (leave blank to disable TSL)' // TODO translate
|
||||||
};
|
};
|
||||||
|
|
||||||
export default no;
|
export default no;
|
||||||
|
|||||||
@@ -282,7 +282,7 @@ const pl: BaseTranslation = {
|
|||||||
SCAN_AGAIN: 'Skanuj ponownie',
|
SCAN_AGAIN: 'Skanuj ponownie',
|
||||||
NETWORK_SCANNER: 'Skaner sieci WiFi',
|
NETWORK_SCANNER: 'Skaner sieci WiFi',
|
||||||
NETWORK_NO_WIFI: 'Brak sieci WiFi w zasięgu',
|
NETWORK_NO_WIFI: 'Brak sieci WiFi w zasięgu',
|
||||||
NETWORK_BLANK_SSID: 'pozostaw puste aby wyłączyć WiFi',
|
NETWORK_BLANK_SSID: 'pozostaw puste aby wyłączyć WiFi', // and enable ETH // TODO translate
|
||||||
TX_POWER: 'Moc nadawania',
|
TX_POWER: 'Moc nadawania',
|
||||||
HOSTNAME: 'Nazwa w sieci',
|
HOSTNAME: 'Nazwa w sieci',
|
||||||
NETWORK_DISABLE_SLEEP: 'Wyłącz tryb uśpienia WiFi',
|
NETWORK_DISABLE_SLEEP: 'Wyłącz tryb uśpienia WiFi',
|
||||||
@@ -322,8 +322,8 @@ const pl: BaseTranslation = {
|
|||||||
ENTITIES_UPDATED: 'Niestandardowe encje zostały uaktualnione.',
|
ENTITIES_UPDATED: 'Niestandardowe encje zostały uaktualnione.',
|
||||||
WRITEABLE: 'zapisywalna',
|
WRITEABLE: 'zapisywalna',
|
||||||
SHOWING: 'Wyświetlane',
|
SHOWING: 'Wyświetlane',
|
||||||
SEARCH: 'Szukaj'
|
SEARCH: 'Szukaj',
|
||||||
|
CERT: 'TSL root certificate (leave blank to disable TSL)' // TODO translate
|
||||||
};
|
};
|
||||||
|
|
||||||
export default pl;
|
export default pl;
|
||||||
|
|||||||
@@ -282,7 +282,7 @@ const sv: Translation = {
|
|||||||
SCAN_AGAIN: 'Sök igen',
|
SCAN_AGAIN: 'Sök igen',
|
||||||
NETWORK_SCANNER: 'Hittade nätverk',
|
NETWORK_SCANNER: 'Hittade nätverk',
|
||||||
NETWORK_NO_WIFI: 'Inga WiFi-nätverk hittades',
|
NETWORK_NO_WIFI: 'Inga WiFi-nätverk hittades',
|
||||||
NETWORK_BLANK_SSID: 'lämna blankt för att inaktivera WiFi',
|
NETWORK_BLANK_SSID: 'lämna blankt för att inaktivera WiFi', // and enable ETH // TODO translate
|
||||||
TX_POWER: 'Tx Effekt',
|
TX_POWER: 'Tx Effekt',
|
||||||
HOSTNAME: 'Värdnamn',
|
HOSTNAME: 'Värdnamn',
|
||||||
NETWORK_DISABLE_SLEEP: 'Inaktivera sömnläge',
|
NETWORK_DISABLE_SLEEP: 'Inaktivera sömnläge',
|
||||||
@@ -322,8 +322,8 @@ const sv: Translation = {
|
|||||||
ENTITIES_UPDATED: 'Entities Updated', // TODO translate
|
ENTITIES_UPDATED: 'Entities Updated', // TODO translate
|
||||||
WRITEABLE: 'Writeable', // TODO translate
|
WRITEABLE: 'Writeable', // TODO translate
|
||||||
SHOWING: 'Showing', // TODO translate
|
SHOWING: 'Showing', // TODO translate
|
||||||
SEARCH: 'Search' // TODO translate
|
SEARCH: 'Search', // TODO translate
|
||||||
|
CERT: 'TSL root certificate (leave blank to disable TSL)' // TODO translate
|
||||||
};
|
};
|
||||||
|
|
||||||
export default sv;
|
export default sv;
|
||||||
|
|||||||
@@ -282,7 +282,7 @@ const tr: Translation = {
|
|||||||
SCAN_AGAIN: 'Tekrar tara',
|
SCAN_AGAIN: 'Tekrar tara',
|
||||||
NETWORK_SCANNER: 'Ağ Tarayıcısı',
|
NETWORK_SCANNER: 'Ağ Tarayıcısı',
|
||||||
NETWORK_NO_WIFI: 'Hiçbir Kablosuz Ağ bulunamadı',
|
NETWORK_NO_WIFI: 'Hiçbir Kablosuz Ağ bulunamadı',
|
||||||
NETWORK_BLANK_SSID: 'Kablosuz ağı devre dışı bırakmak için boş bırakın',
|
NETWORK_BLANK_SSID: 'Kablosuz ağı devre dışı bırakmak için boş bırakın', // and enable ETH // TODO translate
|
||||||
TX_POWER: 'Aktarım gücü',
|
TX_POWER: 'Aktarım gücü',
|
||||||
HOSTNAME: 'Ana Makine Adı',
|
HOSTNAME: 'Ana Makine Adı',
|
||||||
NETWORK_DISABLE_SLEEP: 'Kablosuz uyku modunu devre dışına al',
|
NETWORK_DISABLE_SLEEP: 'Kablosuz uyku modunu devre dışına al',
|
||||||
@@ -322,8 +322,8 @@ const tr: Translation = {
|
|||||||
ENTITIES_UPDATED: 'Entities Updated', // TODO translate
|
ENTITIES_UPDATED: 'Entities Updated', // TODO translate
|
||||||
WRITEABLE: 'Writeable', // TODO translate
|
WRITEABLE: 'Writeable', // TODO translate
|
||||||
SHOWING: 'Showing', // TODO translate
|
SHOWING: 'Showing', // TODO translate
|
||||||
SEARCH: 'Search' // TODO translate
|
SEARCH: 'Search', // TODO translate
|
||||||
|
CERT: 'TSL root certificate (leave blank to disable TSL)' // TODO translate
|
||||||
};
|
};
|
||||||
|
|
||||||
export default tr;
|
export default tr;
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ export interface MqttSettings {
|
|||||||
host: string;
|
host: string;
|
||||||
port: number;
|
port: number;
|
||||||
base: string;
|
base: string;
|
||||||
|
rootCA: string;
|
||||||
username: string;
|
username: string;
|
||||||
password: string;
|
password: string;
|
||||||
client_id: string;
|
client_id: string;
|
||||||
|
|||||||
@@ -59,10 +59,17 @@ class ESP8266React {
|
|||||||
return &_mqttSettingsService;
|
return &_mqttSettingsService;
|
||||||
}
|
}
|
||||||
|
|
||||||
espMqttClient * getMqttClient() {
|
MqttClient * getMqttClient() {
|
||||||
return _mqttSettingsService.getMqttClient();
|
return _mqttSettingsService.getMqttClient();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setWill(const char * will_topic) {
|
||||||
|
_mqttSettingsService.setWill(will_topic);
|
||||||
|
}
|
||||||
|
void onMessage(espMqttClientTypes::OnMessageCallback callback) {
|
||||||
|
_mqttSettingsService.onMessage(callback);
|
||||||
|
}
|
||||||
|
|
||||||
void factoryReset() {
|
void factoryReset() {
|
||||||
_factoryResetService.factoryReset();
|
_factoryResetService.factoryReset();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#include "../../src/emsesp_stub.hpp" // proddy added
|
#include "../../src/emsesp_stub.hpp" // proddy added
|
||||||
|
|
||||||
using namespace std::placeholders; // for `_1` etc
|
using namespace std::placeholders; // for `_1` etc
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retains a copy of the cstr provided in the pointer provided using dynamic allocation.
|
* Retains a copy of the cstr provided in the pointer provided using dynamic allocation.
|
||||||
@@ -34,10 +34,8 @@ MqttSettingsService::MqttSettingsService(AsyncWebServer * server, FS * fs, Secur
|
|||||||
, _reconfigureMqtt(false)
|
, _reconfigureMqtt(false)
|
||||||
, _disconnectedAt(0)
|
, _disconnectedAt(0)
|
||||||
, _disconnectReason(espMqttClientTypes::DisconnectReason::TCP_DISCONNECTED)
|
, _disconnectReason(espMqttClientTypes::DisconnectReason::TCP_DISCONNECTED)
|
||||||
, _mqttClient(espMqttClientTypes::UseInternalTask::NO) {
|
, _mqttClient(nullptr) {
|
||||||
WiFi.onEvent(std::bind(&MqttSettingsService::WiFiEvent, this, _1, _2));
|
WiFi.onEvent(std::bind(&MqttSettingsService::WiFiEvent, this, _1, _2));
|
||||||
_mqttClient.onConnect(std::bind(&MqttSettingsService::onMqttConnect, this, _1));
|
|
||||||
_mqttClient.onDisconnect(std::bind(&MqttSettingsService::onMqttDisconnect, this, _1));
|
|
||||||
addUpdateHandler([&](const String & originId) { onConfigUpdated(); }, false);
|
addUpdateHandler([&](const String & originId) { onConfigUpdated(); }, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,18 +44,27 @@ MqttSettingsService::~MqttSettingsService() {
|
|||||||
|
|
||||||
void MqttSettingsService::begin() {
|
void MqttSettingsService::begin() {
|
||||||
_fsPersistence.readFromFS();
|
_fsPersistence.readFromFS();
|
||||||
|
if (_mqttClient != nullptr) {
|
||||||
|
delete _mqttClient;
|
||||||
|
}
|
||||||
|
if (_state.rootCA.length() > 0) {
|
||||||
|
_mqttClient = static_cast<MqttClient *>(new espMqttClientSecure(espMqttClientTypes::UseInternalTask::NO));
|
||||||
|
static_cast<espMqttClientSecure *>(_mqttClient)->onConnect(std::bind(&MqttSettingsService::onMqttConnect, this, _1));
|
||||||
|
static_cast<espMqttClientSecure *>(_mqttClient)->onDisconnect(std::bind(&MqttSettingsService::onMqttDisconnect, this, _1));
|
||||||
|
} else {
|
||||||
|
_mqttClient = static_cast<MqttClient *>(new espMqttClient(espMqttClientTypes::UseInternalTask::NO));
|
||||||
|
static_cast<espMqttClient *>(_mqttClient)->onConnect(std::bind(&MqttSettingsService::onMqttConnect, this, _1));
|
||||||
|
static_cast<espMqttClient *>(_mqttClient)->onDisconnect(std::bind(&MqttSettingsService::onMqttDisconnect, this, _1));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MqttSettingsService::loop() {
|
void MqttSettingsService::loop() {
|
||||||
if (_reconfigureMqtt || (_disconnectedAt && (uint32_t)(uuid::get_uptime() - _disconnectedAt) >= MQTT_RECONNECTION_DELAY)) {
|
if (_reconfigureMqtt || (_disconnectedAt && (uint32_t)(uuid::get_uptime() - _disconnectedAt) >= MQTT_RECONNECTION_DELAY)) {
|
||||||
// reconfigure MQTT client
|
// reconfigure MQTT client
|
||||||
_disconnectedAt = uuid::get_uptime();
|
_disconnectedAt = configureMqtt() ? 0 : uuid::get_uptime();
|
||||||
if (configureMqtt()) {
|
|
||||||
_disconnectedAt = 0;
|
|
||||||
}
|
|
||||||
_reconfigureMqtt = false;
|
_reconfigureMqtt = false;
|
||||||
}
|
}
|
||||||
_mqttClient.loop();
|
_mqttClient->loop();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MqttSettingsService::isEnabled() {
|
bool MqttSettingsService::isEnabled() {
|
||||||
@@ -65,19 +72,35 @@ bool MqttSettingsService::isEnabled() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool MqttSettingsService::isConnected() {
|
bool MqttSettingsService::isConnected() {
|
||||||
return _mqttClient.connected();
|
return _mqttClient->connected();
|
||||||
}
|
}
|
||||||
|
|
||||||
const char * MqttSettingsService::getClientId() {
|
const char * MqttSettingsService::getClientId() {
|
||||||
return _mqttClient.getClientId();
|
return _mqttClient->getClientId();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MqttSettingsService::setWill(const char * topic) {
|
||||||
|
if (_state.rootCA.length() > 0) {
|
||||||
|
static_cast<espMqttClientSecure *>(_mqttClient)->setWill(topic, 1, true, "offline");
|
||||||
|
} else {
|
||||||
|
static_cast<espMqttClient *>(_mqttClient)->setWill(topic, 1, true, "offline");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MqttSettingsService::onMessage(espMqttClientTypes::OnMessageCallback callback) {
|
||||||
|
if (_state.rootCA.length() > 0) {
|
||||||
|
static_cast<espMqttClientSecure *>(_mqttClient)->onMessage(callback);
|
||||||
|
} else {
|
||||||
|
static_cast<espMqttClient *>(_mqttClient)->onMessage(callback);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
espMqttClientTypes::DisconnectReason MqttSettingsService::getDisconnectReason() {
|
espMqttClientTypes::DisconnectReason MqttSettingsService::getDisconnectReason() {
|
||||||
return _disconnectReason;
|
return _disconnectReason;
|
||||||
}
|
}
|
||||||
|
|
||||||
espMqttClient * MqttSettingsService::getMqttClient() {
|
MqttClient * MqttSettingsService::getMqttClient() {
|
||||||
return &_mqttClient;
|
return _mqttClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MqttSettingsService::onMqttConnect(bool sessionPresent) {
|
void MqttSettingsService::onMqttConnect(bool sessionPresent) {
|
||||||
@@ -118,7 +141,7 @@ void MqttSettingsService::WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) {
|
|||||||
case ARDUINO_EVENT_ETH_DISCONNECTED:
|
case ARDUINO_EVENT_ETH_DISCONNECTED:
|
||||||
if (_state.enabled) {
|
if (_state.enabled) {
|
||||||
// emsesp::EMSESP::logger().info("Network connection dropped, stopping MQTT client");
|
// emsesp::EMSESP::logger().info("Network connection dropped, stopping MQTT client");
|
||||||
_mqttClient.disconnect(true);
|
_mqttClient->disconnect(true);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -128,29 +151,53 @@ void MqttSettingsService::WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool MqttSettingsService::configureMqtt() {
|
bool MqttSettingsService::configureMqtt() {
|
||||||
|
if (_mqttClient == nullptr) {
|
||||||
|
begin();
|
||||||
|
}
|
||||||
// disconnect if connected
|
// disconnect if connected
|
||||||
_mqttClient.disconnect(true);
|
_mqttClient->disconnect(true);
|
||||||
// only connect if WiFi is connected and MQTT is enabled
|
// only connect if WiFi is connected and MQTT is enabled
|
||||||
if (_state.enabled && emsesp::EMSESP::system_.network_connected() && !_state.host.isEmpty()) {
|
if (_state.enabled && !_state.host.isEmpty()) {
|
||||||
// emsesp::EMSESP::logger().info("Configuring MQTT client");
|
_reconfigureMqtt = false;
|
||||||
_mqttClient.setServer(retainCstr(_state.host.c_str(), &_retainedHost), _state.port);
|
if (_state.rootCA.length() > 0) {
|
||||||
if (_state.username.length() > 0) {
|
// static_cast<espMqttClientSecure *>(_mqttClient)->setInsecure();
|
||||||
_mqttClient.setCredentials(retainCstr(_state.username.c_str(), &_retainedUsername),
|
String cert = "-----BEGIN CERTIFICATE-----\n" + _state.rootCA + "-----END CERTIFICATE-----\n";
|
||||||
retainCstr(_state.password.length() > 0 ? _state.password.c_str() : nullptr, &_retainedPassword));
|
static_cast<espMqttClientSecure *>(_mqttClient)->setCACert(retainCstr(cert.c_str(), &_retainedRootCA));
|
||||||
|
static_cast<espMqttClientSecure *>(_mqttClient)->setServer(retainCstr(_state.host.c_str(), &_retainedHost), _state.port);
|
||||||
|
if (_state.username.length() > 0) {
|
||||||
|
static_cast<espMqttClientSecure *>(_mqttClient)
|
||||||
|
->setCredentials(retainCstr(_state.username.c_str(), &_retainedUsername),
|
||||||
|
retainCstr(_state.password.length() > 0 ? _state.password.c_str() : nullptr, &_retainedPassword));
|
||||||
|
} else {
|
||||||
|
static_cast<espMqttClientSecure *>(_mqttClient)->setCredentials(retainCstr(nullptr, &_retainedUsername), retainCstr(nullptr, &_retainedPassword));
|
||||||
|
}
|
||||||
|
static_cast<espMqttClientSecure *>(_mqttClient)->setClientId(retainCstr(_state.clientId.c_str(), &_retainedClientId));
|
||||||
|
static_cast<espMqttClientSecure *>(_mqttClient)->setKeepAlive(_state.keepAlive);
|
||||||
|
static_cast<espMqttClientSecure *>(_mqttClient)->setCleanSession(_state.cleanSession);
|
||||||
|
return _mqttClient->connect();
|
||||||
} else {
|
} else {
|
||||||
_mqttClient.setCredentials(retainCstr(nullptr, &_retainedUsername), retainCstr(nullptr, &_retainedPassword));
|
// emsesp::EMSESP::logger().info("Configuring MQTT client");
|
||||||
|
static_cast<espMqttClient *>(_mqttClient)->setServer(retainCstr(_state.host.c_str(), &_retainedHost), _state.port);
|
||||||
|
if (_state.username.length() > 0) {
|
||||||
|
static_cast<espMqttClient *>(_mqttClient)
|
||||||
|
->setCredentials(retainCstr(_state.username.c_str(), &_retainedUsername),
|
||||||
|
retainCstr(_state.password.length() > 0 ? _state.password.c_str() : nullptr, &_retainedPassword));
|
||||||
|
} else {
|
||||||
|
static_cast<espMqttClient *>(_mqttClient)->setCredentials(retainCstr(nullptr, &_retainedUsername), retainCstr(nullptr, &_retainedPassword));
|
||||||
|
}
|
||||||
|
static_cast<espMqttClient *>(_mqttClient)->setClientId(retainCstr(_state.clientId.c_str(), &_retainedClientId));
|
||||||
|
static_cast<espMqttClient *>(_mqttClient)->setKeepAlive(_state.keepAlive);
|
||||||
|
static_cast<espMqttClient *>(_mqttClient)->setCleanSession(_state.cleanSession);
|
||||||
|
return _mqttClient->connect();
|
||||||
|
// } else {
|
||||||
|
// emsesp::EMSESP::logger().info("Error configuring MQTT client");
|
||||||
}
|
}
|
||||||
_mqttClient.setClientId(retainCstr(_state.clientId.c_str(), &_retainedClientId));
|
|
||||||
_mqttClient.setKeepAlive(_state.keepAlive);
|
|
||||||
_mqttClient.setCleanSession(_state.cleanSession);
|
|
||||||
return _mqttClient.connect();
|
|
||||||
// } else {
|
|
||||||
// emsesp::EMSESP::logger().info("Error configuring MQTT client");
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MqttSettings::read(MqttSettings & settings, JsonObject & root) {
|
void MqttSettings::read(MqttSettings & settings, JsonObject & root) {
|
||||||
|
root["rootCA"] = settings.rootCA;
|
||||||
root["enabled"] = settings.enabled;
|
root["enabled"] = settings.enabled;
|
||||||
root["host"] = settings.host;
|
root["host"] = settings.host;
|
||||||
root["port"] = settings.port;
|
root["port"] = settings.port;
|
||||||
@@ -182,9 +229,11 @@ void MqttSettings::read(MqttSettings & settings, JsonObject & root) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
StateUpdateResult MqttSettings::update(JsonObject & root, MqttSettings & settings) {
|
StateUpdateResult MqttSettings::update(JsonObject & root, MqttSettings & settings) {
|
||||||
MqttSettings newSettings = {};
|
MqttSettings newSettings = {};
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
|
bool restartNeeded = false;
|
||||||
|
|
||||||
|
newSettings.rootCA = root["rootCA"] | "";
|
||||||
newSettings.enabled = root["enabled"] | FACTORY_MQTT_ENABLED;
|
newSettings.enabled = root["enabled"] | FACTORY_MQTT_ENABLED;
|
||||||
newSettings.host = root["host"] | FACTORY_MQTT_HOST;
|
newSettings.host = root["host"] | FACTORY_MQTT_HOST;
|
||||||
newSettings.port = root["port"] | FACTORY_MQTT_PORT;
|
newSettings.port = root["port"] | FACTORY_MQTT_PORT;
|
||||||
@@ -300,6 +349,11 @@ StateUpdateResult MqttSettings::update(JsonObject & root, MqttSettings & setting
|
|||||||
emsesp::EMSESP::mqtt_.set_publish_time_heartbeat(newSettings.publish_time_heartbeat);
|
emsesp::EMSESP::mqtt_.set_publish_time_heartbeat(newSettings.publish_time_heartbeat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (newSettings.rootCA != settings.rootCA) {
|
||||||
|
changed = true;
|
||||||
|
restartNeeded = true;
|
||||||
|
}
|
||||||
|
|
||||||
// save the new settings
|
// save the new settings
|
||||||
settings = newSettings;
|
settings = newSettings;
|
||||||
|
|
||||||
@@ -307,5 +361,9 @@ StateUpdateResult MqttSettings::update(JsonObject & root, MqttSettings & setting
|
|||||||
emsesp::EMSESP::mqtt_.reset_mqtt();
|
emsesp::EMSESP::mqtt_.reset_mqtt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (restartNeeded) {
|
||||||
|
return StateUpdateResult::CHANGED_RESTART; // tell WebUI that a restart is needed
|
||||||
|
}
|
||||||
|
|
||||||
return StateUpdateResult::CHANGED;
|
return StateUpdateResult::CHANGED;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ class MqttSettings {
|
|||||||
bool enabled;
|
bool enabled;
|
||||||
String host;
|
String host;
|
||||||
uint16_t port;
|
uint16_t port;
|
||||||
|
String rootCA;
|
||||||
|
|
||||||
// username and password
|
// username and password
|
||||||
String username;
|
String username;
|
||||||
@@ -110,7 +111,9 @@ class MqttSettingsService : public StatefulService<MqttSettings> {
|
|||||||
bool isConnected();
|
bool isConnected();
|
||||||
const char * getClientId();
|
const char * getClientId();
|
||||||
espMqttClientTypes::DisconnectReason getDisconnectReason();
|
espMqttClientTypes::DisconnectReason getDisconnectReason();
|
||||||
espMqttClient * getMqttClient();
|
MqttClient * getMqttClient();
|
||||||
|
void setWill(const char * topic);
|
||||||
|
void onMessage(espMqttClientTypes::OnMessageCallback callback);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void onConfigUpdated();
|
void onConfigUpdated();
|
||||||
@@ -125,6 +128,7 @@ class MqttSettingsService : public StatefulService<MqttSettings> {
|
|||||||
char * _retainedClientId;
|
char * _retainedClientId;
|
||||||
char * _retainedUsername;
|
char * _retainedUsername;
|
||||||
char * _retainedPassword;
|
char * _retainedPassword;
|
||||||
|
char * _retainedRootCA;
|
||||||
|
|
||||||
// variable to help manage connection
|
// variable to help manage connection
|
||||||
bool _reconfigureMqtt;
|
bool _reconfigureMqtt;
|
||||||
@@ -134,7 +138,7 @@ class MqttSettingsService : public StatefulService<MqttSettings> {
|
|||||||
espMqttClientTypes::DisconnectReason _disconnectReason;
|
espMqttClientTypes::DisconnectReason _disconnectReason;
|
||||||
|
|
||||||
// the MQTT client instance
|
// the MQTT client instance
|
||||||
espMqttClient _mqttClient;
|
MqttClient * _mqttClient = nullptr;
|
||||||
|
|
||||||
void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info);
|
void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info);
|
||||||
void onMqttConnect(bool sessionPresent);
|
void onMqttConnect(bool sessionPresent);
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
namespace emsesp {
|
namespace emsesp {
|
||||||
|
|
||||||
espMqttClient * Mqtt::mqttClient_;
|
MqttClient * Mqtt::mqttClient_;
|
||||||
|
|
||||||
// static parameters we make global
|
// static parameters we make global
|
||||||
std::string Mqtt::mqtt_base_;
|
std::string Mqtt::mqtt_base_;
|
||||||
@@ -387,9 +387,9 @@ void Mqtt::start() {
|
|||||||
snprintf(will_topic, MQTT_TOPIC_MAX_SIZE, "status");
|
snprintf(will_topic, MQTT_TOPIC_MAX_SIZE, "status");
|
||||||
}
|
}
|
||||||
|
|
||||||
mqttClient_->setWill(will_topic, 1, true, "offline"); // with qos 1, retain true
|
EMSESP::esp8266React.setWill(will_topic); // with qos 1, retain true
|
||||||
|
|
||||||
mqttClient_->onMessage(
|
EMSESP::esp8266React.onMessage(
|
||||||
[this](const espMqttClientTypes::MessageProperties & properties, const char * topic, const uint8_t * payload, size_t len, size_t index, size_t total) {
|
[this](const espMqttClientTypes::MessageProperties & properties, const char * topic, const uint8_t * payload, size_t len, size_t index, size_t total) {
|
||||||
on_message(topic, (const char *)payload, len); // receiving mqtt
|
on_message(topic, (const char *)payload, len); // receiving mqtt
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ class Mqtt {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static espMqttClient * client() {
|
static MqttClient * client() {
|
||||||
return mqttClient_;
|
return mqttClient_;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,8 +229,8 @@ class Mqtt {
|
|||||||
private:
|
private:
|
||||||
static uuid::log::Logger logger_;
|
static uuid::log::Logger logger_;
|
||||||
|
|
||||||
static espMqttClient * mqttClient_;
|
static MqttClient * mqttClient_;
|
||||||
static uint32_t mqtt_message_id_;
|
static uint32_t mqtt_message_id_;
|
||||||
|
|
||||||
static bool queue_message(const uint8_t operation, const std::string & topic, const std::string & payload, const bool retain);
|
static bool queue_message(const uint8_t operation, const std::string & topic, const std::string & payload, const bool retain);
|
||||||
static bool queue_publish_message(const std::string & topic, const std::string & payload, const bool retain);
|
static bool queue_publish_message(const std::string & topic, const std::string & payload, const bool retain);
|
||||||
|
|||||||
Reference in New Issue
Block a user