mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-07 08:19:52 +03:00
Merge pull request #797 from MichaelDvP/dev
Some actual additions/changes, see description
This commit is contained in:
722
interface/package-lock.json
generated
722
interface/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -8,7 +8,7 @@
|
||||
"@emotion/styled": "^11.10.5",
|
||||
"@msgpack/msgpack": "^2.8.0",
|
||||
"@mui/icons-material": "^5.10.16",
|
||||
"@mui/material": "^5.10.16",
|
||||
"@mui/material": "^5.10.17",
|
||||
"@table-library/react-table-library": "4.0.23",
|
||||
"@types/lodash": "^4.14.191",
|
||||
"@types/node": "^18.11.11",
|
||||
|
||||
@@ -162,10 +162,6 @@ const MqttSettingsForm: FC = () => {
|
||||
</ValidatedTextField>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<BlockFormControlLabel
|
||||
control={<Checkbox name="multiple_instances" checked={data.multiple_instances} onChange={updateFormValue} />}
|
||||
label={LL.MQTT_MULTIPLE_INSTANCES()}
|
||||
/>
|
||||
<BlockFormControlLabel
|
||||
control={<Checkbox name="clean_session" checked={data.clean_session} onChange={updateFormValue} />}
|
||||
label={LL.MQTT_CLEAN_SESSION()}
|
||||
@@ -224,17 +220,25 @@ const MqttSettingsForm: FC = () => {
|
||||
/>
|
||||
</Grid>
|
||||
{data.ha_enabled && (
|
||||
<Grid item sx={{ pb: 3 }}>
|
||||
<ValidatedTextField
|
||||
name="discovery_prefix"
|
||||
label={LL.MQTT_PUBLISH_TEXT_4()}
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
value={data.discovery_prefix}
|
||||
onChange={updateFormValue}
|
||||
size="small"
|
||||
/>
|
||||
</Grid>
|
||||
<>
|
||||
<Grid item>
|
||||
<BlockFormControlLabel
|
||||
control={<Checkbox name="multiple_instances" checked={data.multiple_instances} onChange={updateFormValue} />}
|
||||
label={LL.MQTT_MULTIPLE_INSTANCES()}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item sx={{ pb: 3 }}>
|
||||
<ValidatedTextField
|
||||
name="discovery_prefix"
|
||||
label={LL.MQTT_PUBLISH_TEXT_4()}
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
value={data.discovery_prefix}
|
||||
onChange={updateFormValue}
|
||||
size="small"
|
||||
/>
|
||||
</Grid>
|
||||
</>
|
||||
)}
|
||||
</Grid>
|
||||
)}
|
||||
@@ -242,6 +246,22 @@ const MqttSettingsForm: FC = () => {
|
||||
{LL.MQTT_PUBLISH_INTERVALS()} (0=auto)
|
||||
</Typography>
|
||||
<Grid container spacing={1} direction="row" justifyContent="flex-start" alignItems="flex-start">
|
||||
<Grid item xs={6} sm={4}>
|
||||
<ValidatedTextField
|
||||
fieldErrors={fieldErrors}
|
||||
name="publish_time_heartbeat"
|
||||
label={LL.MQTT_INT_HEARTBEAT()}
|
||||
InputProps={{
|
||||
endAdornment: <InputAdornment position="end">{LL.SECONDS()}</InputAdornment>
|
||||
}}
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
value={numberValue(data.publish_time_heartbeat)}
|
||||
type="number"
|
||||
onChange={updateFormValue}
|
||||
margin="normal"
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={6} sm={4}>
|
||||
<ValidatedTextField
|
||||
fieldErrors={fieldErrors}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { FC, useContext, useEffect, useState } from 'react';
|
||||
import { useSnackbar } from 'notistack';
|
||||
|
||||
import {
|
||||
Avatar,
|
||||
@@ -18,6 +19,7 @@ import LockOpenIcon from '@mui/icons-material/LockOpen';
|
||||
import DeleteIcon from '@mui/icons-material/Delete';
|
||||
import SaveIcon from '@mui/icons-material/Save';
|
||||
import LockIcon from '@mui/icons-material/Lock';
|
||||
import PowerSettingsNewIcon from '@mui/icons-material/PowerSettingsNew';
|
||||
|
||||
import {
|
||||
BlockFormControlLabel,
|
||||
@@ -25,11 +27,13 @@ import {
|
||||
FormLoader,
|
||||
SectionContent,
|
||||
ValidatedPasswordField,
|
||||
ValidatedTextField
|
||||
ValidatedTextField,
|
||||
MessageBox
|
||||
} from '../../components';
|
||||
import { NetworkSettings } from '../../types';
|
||||
import * as NetworkApi from '../../api/network';
|
||||
import { numberValue, updateValue, useRest } from '../../utils';
|
||||
import * as EMSESP from '../../project/api';
|
||||
|
||||
import { WiFiConnectionContext } from './WiFiConnectionContext';
|
||||
import { isNetworkOpen, networkSecurityMode } from './WiFiNetworkSelector';
|
||||
@@ -38,14 +42,17 @@ import { validate } from '../../validators';
|
||||
import { createNetworkSettingsValidator } from '../../validators/network';
|
||||
|
||||
import { useI18nContext } from '../../i18n/i18n-react';
|
||||
import RestartMonitor from '../system/RestartMonitor';
|
||||
|
||||
const WiFiSettingsForm: FC = () => {
|
||||
const { LL } = useI18nContext();
|
||||
const { enqueueSnackbar } = useSnackbar();
|
||||
|
||||
const { selectedNetwork, deselectNetwork } = useContext(WiFiConnectionContext);
|
||||
|
||||
const [initialized, setInitialized] = useState(false);
|
||||
const { loadData, saving, data, setData, saveData, errorMessage } = useRest<NetworkSettings>({
|
||||
const [restarting, setRestarting] = useState(false);
|
||||
const { loadData, saving, data, setData, saveData, errorMessage, restartNeeded } = useRest<NetworkSettings>({
|
||||
read: NetworkApi.readNetworkSettings,
|
||||
update: NetworkApi.updateNetworkSettings
|
||||
});
|
||||
@@ -62,7 +69,9 @@ const WiFiSettingsForm: FC = () => {
|
||||
bandwidth20: false,
|
||||
tx_power: 20,
|
||||
nosleep: false,
|
||||
enableMDNS: true
|
||||
enableMDNS: true,
|
||||
enableCORS: false,
|
||||
CORSOrigin: '*'
|
||||
});
|
||||
}
|
||||
setInitialized(true);
|
||||
@@ -90,6 +99,15 @@ const WiFiSettingsForm: FC = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const restart = async () => {
|
||||
try {
|
||||
await EMSESP.restart();
|
||||
setRestarting(true);
|
||||
} catch (error) {
|
||||
enqueueSnackbar(LL.PROBLEM_UPDATING(), { variant: 'error' });
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Typography sx={{ pt: 2 }} variant="h6" color="primary">
|
||||
@@ -162,11 +180,6 @@ const WiFiSettingsForm: FC = () => {
|
||||
label={LL.NETWORK_LOW_BAND()}
|
||||
/>
|
||||
|
||||
<BlockFormControlLabel
|
||||
control={<Checkbox name="enableMDNS" checked={data.enableMDNS} onChange={updateFormValue} />}
|
||||
label={LL.NETWORK_USE_DNS()}
|
||||
/>
|
||||
|
||||
<Typography sx={{ pt: 2 }} variant="h6" color="primary">
|
||||
{LL.GENERAL_OPTIONS()}
|
||||
</Typography>
|
||||
@@ -182,6 +195,28 @@ const WiFiSettingsForm: FC = () => {
|
||||
margin="normal"
|
||||
/>
|
||||
|
||||
<BlockFormControlLabel
|
||||
control={<Checkbox name="enableMDNS" checked={data.enableMDNS} onChange={updateFormValue} />}
|
||||
label={LL.NETWORK_USE_DNS()}
|
||||
/>
|
||||
|
||||
<BlockFormControlLabel
|
||||
control={<Checkbox name="enableCORS" checked={data.enableCORS} onChange={updateFormValue} />}
|
||||
label={LL.NETWORK_ENABLE_CORS()}
|
||||
/>
|
||||
{data.enableCORS && (
|
||||
<ValidatedTextField
|
||||
fieldErrors={fieldErrors}
|
||||
name="CORSOrigin"
|
||||
label={LL.NETWORK_CORS_ORIGIN()}
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
value={data.CORSOrigin}
|
||||
onChange={updateFormValue}
|
||||
margin="normal"
|
||||
/>
|
||||
)}
|
||||
|
||||
<BlockFormControlLabel
|
||||
control={<Checkbox name="enableIPv6" checked={data.enableIPv6} onChange={updateFormValue} />}
|
||||
label={LL.NETWORK_ENABLE_IPV6()}
|
||||
@@ -245,6 +280,14 @@ const WiFiSettingsForm: FC = () => {
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{restartNeeded && (
|
||||
<MessageBox my={2} level="warning" message={LL.RESTART_TEXT()}>
|
||||
<Button startIcon={<PowerSettingsNewIcon />} variant="contained" color="error" onClick={restart}>
|
||||
{LL.RESTART()}
|
||||
</Button>
|
||||
</MessageBox>
|
||||
)}
|
||||
{!restartNeeded && (
|
||||
<ButtonRow>
|
||||
<Button
|
||||
startIcon={<SaveIcon />}
|
||||
@@ -257,13 +300,14 @@ const WiFiSettingsForm: FC = () => {
|
||||
{LL.SAVE()}
|
||||
</Button>
|
||||
</ButtonRow>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<SectionContent title={LL.SETTINGS_OF(LL.NETWORK(1))} titleGutter>
|
||||
{content()}
|
||||
{restarting ? <RestartMonitor /> : content()}
|
||||
</SectionContent>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -3,6 +3,7 @@ import type { Translation } from '../i18n-types';
|
||||
/* eslint-disable */
|
||||
|
||||
const de: Translation = {
|
||||
// ...en as Translation,
|
||||
LANGUAGE: 'Sprache',
|
||||
RETRY: 'Neuer Versuch',
|
||||
LOADING: 'Laden',
|
||||
@@ -190,8 +191,8 @@ const de: Translation = {
|
||||
SYSTEM_FACTORY_TEXT_DIALOG: 'Sind Sie sicher alle Einstellungen auf Werkseinstellung zu setzen?',
|
||||
VERSION_CHECK: 'Versionsprüfung',
|
||||
THE_LATEST: 'Die neueste',
|
||||
OFFICIAL: 'official',
|
||||
DEVELOPMENT: 'development',
|
||||
OFFICIAL: 'offizielle',
|
||||
DEVELOPMENT: 'Entwicklungs',
|
||||
VERSION_IS: 'Version ist',
|
||||
RELEASE_NOTES: 'Versionshinweise',
|
||||
EMS_ESP_VER: 'EMS-ESP Version',
|
||||
@@ -245,9 +246,10 @@ const de: Translation = {
|
||||
MQTT_INT_THERMOSTATS: 'Thermostate',
|
||||
MQTT_INT_SOLAR: 'Solarmodule',
|
||||
MQTT_INT_MIXER: 'Mischermodule',
|
||||
MQTT_INT_HEARTBEAT: 'Heartbeat',
|
||||
MQTT_QUEUE: 'MQTT Queue',
|
||||
DEFAULT: 'Standard',
|
||||
MQTT_MULTIPLE_INSTANCES: 'Enable Multiple Instances of EMS-ESP',
|
||||
MQTT_MULTIPLE_INSTANCES: 'Erlaube EMS-ESP Mehrfachinstanzen',
|
||||
MQTT_CLEAN_SESSION: 'Setze `Clean Session`',
|
||||
MQTT_RETAIN_FLAG: 'Setze `Retain flag` immer',
|
||||
INACTIVE: 'Inaktiv',
|
||||
@@ -283,6 +285,8 @@ const de: Translation = {
|
||||
NETWORK_DISABLE_SLEEP: 'Deaktiviere WiFi Schlafmodus',
|
||||
NETWORK_LOW_BAND: 'Verwende niedrige WiFi Bandbreite',
|
||||
NETWORK_USE_DNS: 'Aktiviere mDNS Service',
|
||||
NETWORK_ENABLE_CORS: 'Aktiviere CORS',
|
||||
NETWORK_CORS_ORIGIN: 'CORS origin',
|
||||
NETWORK_ENABLE_IPV6: 'Aktiviere IPv6 Unterstützung',
|
||||
NETWORK_FIXED_IP: 'Feste IP Adresse',
|
||||
NETWORK_GATEWAY: 'Gateway',
|
||||
|
||||
@@ -245,6 +245,7 @@ const en: Translation = {
|
||||
MQTT_INT_THERMOSTATS: 'Thermostats',
|
||||
MQTT_INT_SOLAR: 'Solar Modules',
|
||||
MQTT_INT_MIXER: 'Mixer Modules',
|
||||
MQTT_INT_HEARTBEAT: 'Heartbeat',
|
||||
MQTT_QUEUE: 'MQTT Queue',
|
||||
DEFAULT: 'Default',
|
||||
MQTT_MULTIPLE_INSTANCES: 'Enable Multiple Instances of EMS-ESP',
|
||||
@@ -283,6 +284,8 @@ const en: Translation = {
|
||||
NETWORK_DISABLE_SLEEP: 'Disable WiFi Sleep Mode',
|
||||
NETWORK_LOW_BAND: 'Use Lower WiFi Bandwidth',
|
||||
NETWORK_USE_DNS: 'Enable mDNS Service',
|
||||
NETWORK_ENABLE_CORS: 'Enable CORS',
|
||||
NETWORK_CORS_ORIGIN: 'CORS origin',
|
||||
NETWORK_ENABLE_IPV6: 'Enable IPv6 support',
|
||||
NETWORK_FIXED_IP: 'Use Fixed IP address',
|
||||
NETWORK_GATEWAY: 'Gateway',
|
||||
|
||||
@@ -245,6 +245,7 @@ const nl: Translation = {
|
||||
MQTT_INT_THERMOSTATS: 'Thermostaten',
|
||||
MQTT_INT_SOLAR: 'Solar Modules',
|
||||
MQTT_INT_MIXER: 'Mixer Modules',
|
||||
MQTT_INT_HEARTBEAT: 'Heartbeat',
|
||||
MQTT_QUEUE: 'MQTT Queue',
|
||||
DEFAULT: 'Default',
|
||||
MQTT_MULTIPLE_INSTANCES: 'Enable Multiple Instances of EMS-ESP',
|
||||
@@ -283,6 +284,8 @@ const nl: Translation = {
|
||||
NETWORK_DISABLE_SLEEP: 'WiFi Sleep Mode uitzetten',
|
||||
NETWORK_LOW_BAND: 'Lagere WiFi bandbreedte gebruiken',
|
||||
NETWORK_USE_DNS: 'Activeer mDNS Service',
|
||||
NETWORK_ENABLE_CORS: 'Activeer CORS',
|
||||
NETWORK_CORS_ORIGIN: 'CORS origin',
|
||||
NETWORK_ENABLE_IPV6: 'Activeer IPv6 support',
|
||||
NETWORK_FIXED_IP: 'Gebruik vast IP addres',
|
||||
NETWORK_GATEWAY: 'Gateway',
|
||||
|
||||
@@ -245,6 +245,7 @@ const no: Translation = {
|
||||
MQTT_INT_THERMOSTATS: 'Termostat',
|
||||
MQTT_INT_SOLAR: 'Solpaneler',
|
||||
MQTT_INT_MIXER: 'Blandeventil',
|
||||
MQTT_INT_HEARTBEAT: 'Heartbeat',
|
||||
MQTT_QUEUE: 'MQTT Queue',
|
||||
DEFAULT: 'Standard',
|
||||
MQTT_MULTIPLE_INSTANCES: 'Enable Multiple Instances of EMS-ESP',
|
||||
@@ -283,6 +284,8 @@ const no: Translation = {
|
||||
NETWORK_DISABLE_SLEEP: 'Hindre at trådløst nettverk går i Sleep Mode',
|
||||
NETWORK_LOW_BAND: 'Benytt smalere båndbredde på trådløst nettverk',
|
||||
NETWORK_USE_DNS: 'Aktiviser mDNS Service',
|
||||
NETWORK_ENABLE_CORS: 'Aktiviser CORS',
|
||||
NETWORK_CORS_ORIGIN: 'CORS origin',
|
||||
NETWORK_ENABLE_IPV6: 'Aktiviser IPv6 støtte',
|
||||
NETWORK_FIXED_IP: 'Benytt statisk IP adresse',
|
||||
NETWORK_GATEWAY: 'Gateway',
|
||||
|
||||
@@ -245,6 +245,7 @@ const pl: BaseTranslation = {
|
||||
MQTT_INT_THERMOSTATS: 'Termostaty',
|
||||
MQTT_INT_SOLAR: 'Panele solarne',
|
||||
MQTT_INT_MIXER: 'Mieszacze',
|
||||
MQTT_INT_HEARTBEAT: 'Heartbeat',
|
||||
MQTT_QUEUE: 'Kolejka MQTT',
|
||||
DEFAULT: '{{Pozostałe|Domyślna|}}',
|
||||
MQTT_MULTIPLE_INSTANCES: 'Enable Multiple Instances of EMS-ESP',
|
||||
@@ -283,6 +284,8 @@ const pl: BaseTranslation = {
|
||||
NETWORK_DISABLE_SLEEP: 'Wyłącz tryb usypiania WiFi',
|
||||
NETWORK_LOW_BAND: 'Używaj zmniejszonej przepustowości WiFi',
|
||||
NETWORK_USE_DNS: 'Włącz wsparcie dla mDNS',
|
||||
NETWORK_ENABLE_CORS: 'Włącz wsparcie dla CORS',
|
||||
NETWORK_CORS_ORIGIN: 'CORS origin',
|
||||
NETWORK_ENABLE_IPV6: 'Włącz wsparcie dla IPv6',
|
||||
NETWORK_FIXED_IP: 'Użyj stałego adresu IP',
|
||||
NETWORK_GATEWAY: 'Brama',
|
||||
|
||||
@@ -245,6 +245,7 @@ const se: Translation = {
|
||||
MQTT_INT_THERMOSTATS: 'Termostater',
|
||||
MQTT_INT_SOLAR: 'Solpaneler',
|
||||
MQTT_INT_MIXER: 'Blandarventiler',
|
||||
MQTT_INT_HEARTBEAT: 'Heartbeat',
|
||||
MQTT_QUEUE: 'MQTT Queue',
|
||||
DEFAULT: 'Standard',
|
||||
MQTT_MULTIPLE_INSTANCES: 'Enable Multiple Instances of EMS-ESP',
|
||||
@@ -283,6 +284,8 @@ const se: Translation = {
|
||||
NETWORK_DISABLE_SLEEP: 'Inaktivera sömnläge',
|
||||
NETWORK_LOW_BAND: 'Använd lägre bandbredd',
|
||||
NETWORK_USE_DNS: 'Aktivera mDNS-tjänsten',
|
||||
NETWORK_ENABLE_CORS: 'Aktivera CORS',
|
||||
NETWORK_CORS_ORIGIN: 'CORS origin',
|
||||
NETWORK_ENABLE_IPV6: 'Aktivera IPv6-support',
|
||||
NETWORK_FIXED_IP: 'Använd statiskt IP',
|
||||
NETWORK_GATEWAY: 'Gateway',
|
||||
|
||||
@@ -36,6 +36,7 @@ export interface MqttSettings {
|
||||
publish_time_mixer: number;
|
||||
publish_time_other: number;
|
||||
publish_time_sensor: number;
|
||||
publish_time_heartbeat: number;
|
||||
mqtt_qos: number;
|
||||
mqtt_retain: boolean;
|
||||
ha_enabled: boolean;
|
||||
|
||||
@@ -48,6 +48,8 @@ export interface NetworkSettings {
|
||||
dns_ip_1?: string;
|
||||
dns_ip_2?: string;
|
||||
enableMDNS: boolean;
|
||||
enableCORS: boolean;
|
||||
CORSOrigin: string;
|
||||
}
|
||||
|
||||
export interface WiFiNetworkList {
|
||||
|
||||
@@ -11,5 +11,9 @@ export const MQTT_SETTINGS_VALIDATOR = new Schema({
|
||||
keep_alive: [
|
||||
{ required: true, message: 'Keep alive is required' },
|
||||
{ type: 'number', min: 1, max: 86400, message: 'Keep alive must be between 1 and 86400' }
|
||||
],
|
||||
publish_time_heartbeat: [
|
||||
{ required: true, message: 'Heartbeat is required' },
|
||||
{ type: 'number', min: 10, max: 86400, message: 'Heartbeat must be between 10 and 86400' }
|
||||
]
|
||||
});
|
||||
|
||||
@@ -46,6 +46,13 @@ ESP8266React::ESP8266React(AsyncWebServer * server, FS * fs)
|
||||
|
||||
void ESP8266React::begin() {
|
||||
_networkSettingsService.begin();
|
||||
_networkSettingsService.read([&](NetworkSettings & networkSettings) {
|
||||
if (networkSettings.enableCORS) {
|
||||
DefaultHeaders::Instance().addHeader("Access-Control-Allow-Origin", networkSettings.CORSOrigin);
|
||||
DefaultHeaders::Instance().addHeader("Access-Control-Allow-Headers", "Accept, Content-Type, Authorization");
|
||||
DefaultHeaders::Instance().addHeader("Access-Control-Allow-Credentials", "true");
|
||||
}
|
||||
});
|
||||
_apSettingsService.begin();
|
||||
_ntpSettingsService.begin();
|
||||
_otaSettingsService.begin();
|
||||
|
||||
@@ -163,6 +163,7 @@ void MqttSettings::read(MqttSettings & settings, JsonObject & root) {
|
||||
root["publish_time_mixer"] = settings.publish_time_mixer;
|
||||
root["publish_time_other"] = settings.publish_time_other;
|
||||
root["publish_time_sensor"] = settings.publish_time_sensor;
|
||||
root["publish_time_heartbeat"] = settings.publish_time_heartbeat;
|
||||
root["mqtt_qos"] = settings.mqtt_qos;
|
||||
root["mqtt_retain"] = settings.mqtt_retain;
|
||||
root["ha_enabled"] = settings.ha_enabled;
|
||||
@@ -197,6 +198,7 @@ StateUpdateResult MqttSettings::update(JsonObject & root, MqttSettings & setting
|
||||
newSettings.publish_time_mixer = root["publish_time_mixer"] | EMSESP_DEFAULT_PUBLISH_TIME;
|
||||
newSettings.publish_time_other = root["publish_time_other"] | EMSESP_DEFAULT_PUBLISH_TIME;
|
||||
newSettings.publish_time_sensor = root["publish_time_sensor"] | EMSESP_DEFAULT_PUBLISH_TIME;
|
||||
newSettings.publish_time_heartbeat = root["publish_time_heartbeat"] | EMSESP_DEFAULT_PUBLISH_HEARTBEAT;
|
||||
|
||||
newSettings.ha_enabled = root["ha_enabled"] | EMSESP_DEFAULT_HA_ENABLED;
|
||||
newSettings.nested_format = root["nested_format"] | EMSESP_DEFAULT_NESTED_FORMAT;
|
||||
@@ -285,6 +287,11 @@ StateUpdateResult MqttSettings::update(JsonObject & root, MqttSettings & setting
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (newSettings.publish_time_heartbeat != settings.publish_time_heartbeat) {
|
||||
emsesp::EMSESP::mqtt_.set_publish_time_heartbeat(newSettings.publish_time_heartbeat);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
emsesp::EMSESP::mqtt_.reset_mqtt();
|
||||
}
|
||||
|
||||
@@ -90,6 +90,7 @@ class MqttSettings {
|
||||
uint16_t publish_time_mixer;
|
||||
uint16_t publish_time_other;
|
||||
uint16_t publish_time_sensor;
|
||||
uint16_t publish_time_heartbeat;
|
||||
uint8_t mqtt_qos;
|
||||
bool mqtt_retain;
|
||||
bool ha_enabled;
|
||||
|
||||
@@ -39,6 +39,8 @@ class NetworkSettings {
|
||||
int8_t tx_power;
|
||||
bool nosleep;
|
||||
bool enableMDNS;
|
||||
bool enableCORS;
|
||||
String CORSOrigin;
|
||||
|
||||
// optional configuration for static IP address
|
||||
IPAddress localIP;
|
||||
@@ -58,6 +60,8 @@ class NetworkSettings {
|
||||
root["tx_power"] = settings.tx_power;
|
||||
root["nosleep"] = settings.nosleep;
|
||||
root["enableMDNS"] = settings.enableMDNS;
|
||||
root["enableCORS"] = settings.enableCORS;
|
||||
root["CORSOrigin"] = settings.CORSOrigin;
|
||||
|
||||
// extended settings
|
||||
JsonUtils::writeIP(root, "local_ip", settings.localIP);
|
||||
@@ -68,6 +72,8 @@ class NetworkSettings {
|
||||
}
|
||||
|
||||
static StateUpdateResult update(JsonObject & root, NetworkSettings & settings) {
|
||||
auto enableCORS = settings.enableCORS;
|
||||
auto CORSOrigin = settings.CORSOrigin;
|
||||
settings.ssid = root["ssid"] | FACTORY_WIFI_SSID;
|
||||
settings.password = root["password"] | FACTORY_WIFI_PASSWORD;
|
||||
settings.hostname = root["hostname"] | FACTORY_WIFI_HOSTNAME;
|
||||
@@ -77,6 +83,8 @@ class NetworkSettings {
|
||||
settings.tx_power = root["tx_power"] | 20;
|
||||
settings.nosleep = root["nosleep"] | false;
|
||||
settings.enableMDNS = root["enableMDNS"] | true;
|
||||
settings.enableCORS = root["enableCORS"] | false;
|
||||
settings.CORSOrigin = root["CORSOrigin"] | "*";
|
||||
|
||||
// extended settings
|
||||
JsonUtils::readIP(root, "local_ip", settings.localIP);
|
||||
@@ -97,6 +105,9 @@ class NetworkSettings {
|
||||
if (settings.staticIPConfig && (IPUtils::isNotSet(settings.localIP) || IPUtils::isNotSet(settings.gatewayIP) || IPUtils::isNotSet(settings.subnetMask))) {
|
||||
settings.staticIPConfig = false;
|
||||
}
|
||||
if (enableCORS != settings.enableCORS || CORSOrigin != settings.CORSOrigin) {
|
||||
return StateUpdateResult::CHANGED_RESTART; // tell WebUI that a restart is needed
|
||||
}
|
||||
|
||||
return StateUpdateResult::CHANGED;
|
||||
}
|
||||
|
||||
@@ -89,6 +89,7 @@ class DummySettings {
|
||||
uint16_t publish_time_mixer = 10;
|
||||
uint16_t publish_time_other = 10;
|
||||
uint16_t publish_time_sensor = 10;
|
||||
uint16_t publish_time_heartbeat = 60;
|
||||
|
||||
String hostname = "ems-esp";
|
||||
String jwtSecret = "ems-esp";
|
||||
@@ -102,6 +103,8 @@ class DummySettings {
|
||||
String dnsIP2 = "";
|
||||
bool enableIPv6 = false;
|
||||
bool enableMDNS = true;
|
||||
bool enableCORS = false;
|
||||
String CORSOrigin = "*";
|
||||
|
||||
uint8_t phy_type = 0;
|
||||
uint8_t eth_power = 0; // 0 means -1
|
||||
|
||||
@@ -122,7 +122,11 @@ network_settings = {
|
||||
hostname: 'ems-esp',
|
||||
nosleep: true,
|
||||
tx_power: 20,
|
||||
bandwidth20: false,
|
||||
static_ip_config: false,
|
||||
enableMDNS: true,
|
||||
enableCORS: false,
|
||||
CORSOrigin: '*',
|
||||
}
|
||||
const network_status = {
|
||||
status: 3,
|
||||
@@ -226,6 +230,7 @@ mqtt_settings = {
|
||||
publish_time_mixer: 10,
|
||||
publish_time_other: 10,
|
||||
publish_time_sensor: 10,
|
||||
publish_time_heartbeat: 60,
|
||||
mqtt_qos: 0,
|
||||
mqtt_retain: false,
|
||||
ha_enabled: true,
|
||||
|
||||
@@ -296,7 +296,7 @@ void AnalogSensor::loop() {
|
||||
}
|
||||
|
||||
// update analog information name and offset
|
||||
bool AnalogSensor::update(uint8_t gpio, const std::string & name, float offset, float factor, uint8_t uom, int8_t type) {
|
||||
bool AnalogSensor::update(uint8_t gpio, const std::string & name, double offset, double factor, uint8_t uom, int8_t type) {
|
||||
boolean found_sensor = false; // see if we can find the sensor in our customization list
|
||||
|
||||
EMSESP::webCustomizationService.update(
|
||||
@@ -375,7 +375,7 @@ void AnalogSensor::publish_sensor(const Sensor & sensor) const {
|
||||
snprintf(topic, sizeof(topic), "%s%s/%s", F_(analogsensor), "_data", sensor.name().c_str());
|
||||
}
|
||||
char payload[10];
|
||||
Mqtt::publish(topic, Helpers::render_value(payload, sensor.value(), 2)); // always publish as floats
|
||||
Mqtt::publish(topic, Helpers::render_value(payload, sensor.value(), 2)); // always publish as doubles
|
||||
}
|
||||
}
|
||||
|
||||
@@ -422,7 +422,7 @@ void AnalogSensor::publish_values(const bool force) {
|
||||
case AnalogType::PWM_0:
|
||||
case AnalogType::PWM_1:
|
||||
case AnalogType::PWM_2:
|
||||
dataSensor["value"] = serialized(Helpers::render_value(s, sensor.value(), 2)); // float
|
||||
dataSensor["value"] = serialized(Helpers::render_value(s, sensor.value(), 2)); // double
|
||||
break;
|
||||
default:
|
||||
dataSensor["value"] = (uint8_t)sensor.value(); // convert to char for 1 or 0
|
||||
@@ -586,7 +586,7 @@ bool AnalogSensor::command_info(const char * value, const int8_t id, JsonObject
|
||||
}
|
||||
|
||||
// this creates the sensor, initializing everything
|
||||
AnalogSensor::Sensor::Sensor(const uint8_t gpio, const std::string & name, const float offset, const float factor, const uint8_t uom, const int8_t type)
|
||||
AnalogSensor::Sensor::Sensor(const uint8_t gpio, const std::string & name, const double offset, const double factor, const uint8_t uom, const int8_t type)
|
||||
: gpio_(gpio)
|
||||
, name_(name)
|
||||
, offset_(offset)
|
||||
|
||||
@@ -35,10 +35,10 @@ class AnalogSensor {
|
||||
public:
|
||||
class Sensor {
|
||||
public:
|
||||
Sensor(const uint8_t gpio, const std::string & name, const float offset, const float factor, const uint8_t uom, const int8_t type);
|
||||
Sensor(const uint8_t gpio, const std::string & name, const double offset, const double factor, const uint8_t uom, const int8_t type);
|
||||
~Sensor() = default;
|
||||
|
||||
void set_offset(const float offset) {
|
||||
void set_offset(const double offset) {
|
||||
offset_ = offset;
|
||||
}
|
||||
|
||||
@@ -52,23 +52,23 @@ class AnalogSensor {
|
||||
return gpio_;
|
||||
}
|
||||
|
||||
float value() const {
|
||||
double value() const {
|
||||
return value_;
|
||||
}
|
||||
|
||||
void set_value(float value) {
|
||||
void set_value(const double value) {
|
||||
value_ = value;
|
||||
}
|
||||
|
||||
float factor() const {
|
||||
double factor() const {
|
||||
return factor_;
|
||||
}
|
||||
|
||||
void set_factor(float factor) {
|
||||
void set_factor(const double factor) {
|
||||
factor_ = factor;
|
||||
}
|
||||
|
||||
float offset() const {
|
||||
double offset() const {
|
||||
return offset_;
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ class AnalogSensor {
|
||||
return type_;
|
||||
}
|
||||
|
||||
void set_type(int8_t type) {
|
||||
void set_type(const int8_t type) {
|
||||
type_ = type;
|
||||
}
|
||||
|
||||
@@ -101,10 +101,10 @@ class AnalogSensor {
|
||||
private:
|
||||
uint8_t gpio_;
|
||||
std::string name_;
|
||||
float offset_;
|
||||
float factor_;
|
||||
double offset_;
|
||||
double factor_;
|
||||
uint8_t uom_;
|
||||
float value_; // float because of the factor is a float
|
||||
double value_; // double because of the factor is a double
|
||||
int8_t type_;
|
||||
};
|
||||
|
||||
@@ -157,7 +157,7 @@ class AnalogSensor {
|
||||
return sensors_.size();
|
||||
}
|
||||
|
||||
bool update(uint8_t gpio, const std::string & name, float offset, float factor, uint8_t uom, int8_t type);
|
||||
bool update(uint8_t gpio, const std::string & name, double offset, double factor, uint8_t uom, int8_t type);
|
||||
bool get_value_info(JsonObject & output, const char * cmd, const int8_t id) const;
|
||||
|
||||
#ifdef EMSESP_DEBUG
|
||||
|
||||
@@ -157,6 +157,10 @@
|
||||
#define EMSESP_DEFAULT_PUBLISH_TIME 10
|
||||
#endif
|
||||
|
||||
#ifndef EMSESP_DEFAULT_PUBLISH_HEARTBEAT
|
||||
#define EMSESP_DEFAULT_PUBLISH_HEARTBEAT 60
|
||||
#endif
|
||||
|
||||
#ifndef EMSESP_DEFAULT_NESTED_FORMAT
|
||||
#define EMSESP_DEFAULT_NESTED_FORMAT 1
|
||||
#endif
|
||||
|
||||
@@ -244,7 +244,7 @@ char * Helpers::render_value(char * result, uint8_t value, int8_t format, const
|
||||
|
||||
// float: convert float to char
|
||||
// format is the precision, 0 to 8
|
||||
char * Helpers::render_value(char * result, const float value, const int8_t format) {
|
||||
char * Helpers::render_value(char * result, const double value, const int8_t format) {
|
||||
if (format > 8) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace emsesp {
|
||||
|
||||
class Helpers {
|
||||
public:
|
||||
static char * render_value(char * result, const float value, const int8_t format); // format is the precision
|
||||
static char * render_value(char * result, const double value, const int8_t format); // format is the precision
|
||||
static char * render_value(char * result, const uint8_t value, const int8_t format, const uint8_t fahrenheit = 0);
|
||||
static char * render_value(char * result, const int8_t value, const int8_t format, const uint8_t fahrenheit = 0);
|
||||
static char * render_value(char * result, const uint16_t value, const int8_t format, const uint8_t fahrenheit = 0);
|
||||
|
||||
18
src/mqtt.cpp
18
src/mqtt.cpp
@@ -36,6 +36,7 @@ uint32_t Mqtt::publish_time_solar_;
|
||||
uint32_t Mqtt::publish_time_mixer_;
|
||||
uint32_t Mqtt::publish_time_sensor_;
|
||||
uint32_t Mqtt::publish_time_other_;
|
||||
uint32_t Mqtt::publish_time_heartbeat_;
|
||||
bool Mqtt::mqtt_enabled_;
|
||||
bool Mqtt::multiple_instances_;
|
||||
bool Mqtt::ha_enabled_;
|
||||
@@ -147,6 +148,12 @@ void Mqtt::loop() {
|
||||
process_queue();
|
||||
}
|
||||
|
||||
// send heartbeat
|
||||
if ((currentMillis - last_publish_heartbeat_ > publish_time_heartbeat_)) {
|
||||
last_publish_heartbeat_ = currentMillis;
|
||||
EMSESP::system_.send_heartbeat(); // send heartbeat
|
||||
}
|
||||
|
||||
// dallas publish on change
|
||||
if (!publish_time_sensor_) {
|
||||
EMSESP::publish_sensor_values(false);
|
||||
@@ -432,6 +439,7 @@ void Mqtt::load_settings() {
|
||||
publish_time_mixer_ = mqttSettings.publish_time_mixer * 1000;
|
||||
publish_time_other_ = mqttSettings.publish_time_other * 1000;
|
||||
publish_time_sensor_ = mqttSettings.publish_time_sensor * 1000;
|
||||
publish_time_heartbeat_ = mqttSettings.publish_time_heartbeat * 1000;
|
||||
});
|
||||
|
||||
// create basename from base
|
||||
@@ -514,6 +522,10 @@ void Mqtt::set_publish_time_sensor(uint16_t publish_time) {
|
||||
publish_time_sensor_ = publish_time * 1000; // convert to milliseconds
|
||||
}
|
||||
|
||||
void Mqtt::set_publish_time_heartbeat(uint16_t publish_time) {
|
||||
publish_time_heartbeat_ = publish_time * 1000; // convert to milliseconds
|
||||
}
|
||||
|
||||
bool Mqtt::get_publish_onchange(uint8_t device_type) {
|
||||
if (publish_single_ && !ha_enabled_) {
|
||||
return false;
|
||||
@@ -653,7 +665,7 @@ std::shared_ptr<const MqttMessage> Mqtt::queue_message(const uint8_t operation,
|
||||
std::shared_ptr<MqttMessage> message;
|
||||
message = std::make_shared<MqttMessage>(operation, topic, payload, retain);
|
||||
|
||||
#ifdef EMSESP_DEBUG
|
||||
#if defined(EMSESP_DEBUG)
|
||||
if (operation == Operation::PUBLISH) {
|
||||
if (message->payload.empty()) {
|
||||
LOG_INFO("[DEBUG] Adding to queue: (Publish) topic='%s' empty payload", message->topic.c_str());
|
||||
@@ -848,7 +860,9 @@ void Mqtt::process_queue() {
|
||||
mqtt_message.retry_count_ + 1,
|
||||
message->payload.size(),
|
||||
packet_id);
|
||||
|
||||
#if defined(EMSESP_DEBUG)
|
||||
LOG_DEBUG("Payload:%s", message->payload.c_str()); // extra message for #784
|
||||
#endif
|
||||
if (packet_id == 0) {
|
||||
// it failed. if we retried n times, give up. remove from queue
|
||||
if (mqtt_message.retry_count_ == (MQTT_PUBLISH_MAX_RETRY - 1)) {
|
||||
|
||||
@@ -65,6 +65,7 @@ class Mqtt {
|
||||
void set_publish_time_mixer(uint16_t publish_time);
|
||||
void set_publish_time_other(uint16_t publish_time);
|
||||
void set_publish_time_sensor(uint16_t publish_time);
|
||||
void set_publish_time_heartbeat(uint16_t publish_time);
|
||||
bool get_publish_onchange(uint8_t device_type);
|
||||
|
||||
enum Operation : uint8_t { PUBLISH, SUBSCRIBE, UNSUBSCRIBE };
|
||||
@@ -292,6 +293,7 @@ class Mqtt {
|
||||
uint32_t last_publish_mixer_ = 0;
|
||||
uint32_t last_publish_other_ = 0;
|
||||
uint32_t last_publish_sensor_ = 0;
|
||||
uint32_t last_publish_heartbeat_ = 0;
|
||||
uint32_t last_publish_queue_ = 0;
|
||||
|
||||
static bool connecting_;
|
||||
@@ -315,6 +317,7 @@ class Mqtt {
|
||||
static uint32_t publish_time_mixer_;
|
||||
static uint32_t publish_time_other_;
|
||||
static uint32_t publish_time_sensor_;
|
||||
static uint32_t publish_time_heartbeat_;
|
||||
static bool mqtt_enabled_;
|
||||
static bool ha_enabled_;
|
||||
static uint8_t nested_format_;
|
||||
|
||||
@@ -512,12 +512,6 @@ void System::loop() {
|
||||
led_monitor(); // check status and report back using the LED
|
||||
system_check(); // check system health
|
||||
|
||||
// send out heartbeat
|
||||
uint32_t currentMillis = uuid::get_uptime();
|
||||
if (!last_heartbeat_ || (currentMillis - last_heartbeat_ > SYSTEM_HEARTBEAT_INTERVAL)) {
|
||||
last_heartbeat_ = currentMillis;
|
||||
send_heartbeat();
|
||||
}
|
||||
#ifndef EMSESP_STANDALONE
|
||||
|
||||
#if defined(EMSESP_DEBUG)
|
||||
@@ -1110,6 +1104,11 @@ bool System::command_info(const char * value, const int8_t id, JsonObject & outp
|
||||
node["enable IPv6"] = settings.enableIPv6;
|
||||
node["low bandwidth"] = settings.bandwidth20;
|
||||
node["disable sleep"] = settings.nosleep;
|
||||
node["enable MDNS"] = settings.enableMDNS;
|
||||
node["enable CORS"] = settings.enableCORS;
|
||||
if (settings.enableCORS) {
|
||||
node["CORS origin"] = settings.CORSOrigin;
|
||||
}
|
||||
});
|
||||
#ifndef EMSESP_STANDALONE
|
||||
EMSESP::esp8266React.getAPSettingsService()->read([&](APSettings & settings) {
|
||||
@@ -1160,6 +1159,7 @@ bool System::command_info(const char * value, const int8_t id, JsonObject & outp
|
||||
node["ha enabled"] = settings.ha_enabled;
|
||||
node["mqtt qos"] = settings.mqtt_qos;
|
||||
node["mqtt retain"] = settings.mqtt_retain;
|
||||
node["publish time heartbeat"] = settings.publish_time_heartbeat;
|
||||
node["publish time boiler"] = settings.publish_time_boiler;
|
||||
node["publish time thermostat"] = settings.publish_time_thermostat;
|
||||
node["publish time solar"] = settings.publish_time_solar;
|
||||
|
||||
@@ -250,7 +250,6 @@ class System {
|
||||
static constexpr uint32_t HEALTHCHECK_LED_FLASH_DUARATION = 150;
|
||||
static constexpr uint8_t HEALTHCHECK_NO_BUS = (1 << 0); // 1
|
||||
static constexpr uint8_t HEALTHCHECK_NO_NETWORK = (1 << 1); // 2
|
||||
static constexpr uint32_t SYSTEM_HEARTBEAT_INTERVAL = 60000; // in milliseconds, how often the MQTT heartbeat is sent (1 min)
|
||||
static constexpr uint8_t LED_ON = HIGH; // LED on
|
||||
|
||||
#ifndef EMSESP_STANDALONE
|
||||
@@ -263,7 +262,6 @@ class System {
|
||||
int8_t wifi_quality(int8_t dBm);
|
||||
|
||||
uint8_t healthcheck_ = HEALTHCHECK_NO_NETWORK | HEALTHCHECK_NO_BUS; // start with all flags set, no wifi and no ems bus connection
|
||||
uint32_t last_heartbeat_ = 0;
|
||||
uint32_t last_system_check_ = 0;
|
||||
|
||||
bool upload_status_ = false; // true if we're in the middle of a OTA firmware upload
|
||||
|
||||
@@ -44,8 +44,8 @@ class AnalogCustomization {
|
||||
public:
|
||||
uint8_t gpio;
|
||||
std::string name;
|
||||
float offset;
|
||||
float factor;
|
||||
double offset;
|
||||
double factor;
|
||||
uint8_t uom; // 0 is none
|
||||
int8_t type; // -1 is for deletion
|
||||
|
||||
|
||||
@@ -284,8 +284,8 @@ void WebDataService::write_analog(AsyncWebServerRequest * request, JsonVariant &
|
||||
|
||||
uint8_t gpio = analog["gpio"]; // this is the unique key, the GPIO
|
||||
std::string name = analog["name"];
|
||||
float factor = analog["factor"];
|
||||
float offset = analog["offset"];
|
||||
double factor = analog["factor"];
|
||||
double offset = analog["offset"];
|
||||
uint8_t uom = analog["uom"];
|
||||
int8_t type = analog["type"];
|
||||
ok = EMSESP::analogsensor_.update(gpio, name, offset, factor, uom, type);
|
||||
|
||||
Reference in New Issue
Block a user