Merge pull request #797 from MichaelDvP/dev

Some actual additions/changes, see description
This commit is contained in:
MichaelDvP
2022-12-09 10:11:40 +01:00
committed by GitHub
30 changed files with 565 additions and 420 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -8,7 +8,7 @@
"@emotion/styled": "^11.10.5", "@emotion/styled": "^11.10.5",
"@msgpack/msgpack": "^2.8.0", "@msgpack/msgpack": "^2.8.0",
"@mui/icons-material": "^5.10.16", "@mui/icons-material": "^5.10.16",
"@mui/material": "^5.10.16", "@mui/material": "^5.10.17",
"@table-library/react-table-library": "4.0.23", "@table-library/react-table-library": "4.0.23",
"@types/lodash": "^4.14.191", "@types/lodash": "^4.14.191",
"@types/node": "^18.11.11", "@types/node": "^18.11.11",

View File

@@ -162,10 +162,6 @@ const MqttSettingsForm: FC = () => {
</ValidatedTextField> </ValidatedTextField>
</Grid> </Grid>
</Grid> </Grid>
<BlockFormControlLabel
control={<Checkbox name="multiple_instances" checked={data.multiple_instances} onChange={updateFormValue} />}
label={LL.MQTT_MULTIPLE_INSTANCES()}
/>
<BlockFormControlLabel <BlockFormControlLabel
control={<Checkbox name="clean_session" checked={data.clean_session} onChange={updateFormValue} />} control={<Checkbox name="clean_session" checked={data.clean_session} onChange={updateFormValue} />}
label={LL.MQTT_CLEAN_SESSION()} label={LL.MQTT_CLEAN_SESSION()}
@@ -224,6 +220,13 @@ const MqttSettingsForm: FC = () => {
/> />
</Grid> </Grid>
{data.ha_enabled && ( {data.ha_enabled && (
<>
<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 }}> <Grid item sx={{ pb: 3 }}>
<ValidatedTextField <ValidatedTextField
name="discovery_prefix" name="discovery_prefix"
@@ -235,6 +238,7 @@ const MqttSettingsForm: FC = () => {
size="small" size="small"
/> />
</Grid> </Grid>
</>
)} )}
</Grid> </Grid>
)} )}
@@ -242,6 +246,22 @@ const MqttSettingsForm: FC = () => {
{LL.MQTT_PUBLISH_INTERVALS()}&nbsp;(0=auto) {LL.MQTT_PUBLISH_INTERVALS()}&nbsp;(0=auto)
</Typography> </Typography>
<Grid container spacing={1} direction="row" justifyContent="flex-start" alignItems="flex-start"> <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}> <Grid item xs={6} sm={4}>
<ValidatedTextField <ValidatedTextField
fieldErrors={fieldErrors} fieldErrors={fieldErrors}

View File

@@ -1,4 +1,5 @@
import { FC, useContext, useEffect, useState } from 'react'; import { FC, useContext, useEffect, useState } from 'react';
import { useSnackbar } from 'notistack';
import { import {
Avatar, Avatar,
@@ -18,6 +19,7 @@ import LockOpenIcon from '@mui/icons-material/LockOpen';
import DeleteIcon from '@mui/icons-material/Delete'; import DeleteIcon from '@mui/icons-material/Delete';
import SaveIcon from '@mui/icons-material/Save'; import SaveIcon from '@mui/icons-material/Save';
import LockIcon from '@mui/icons-material/Lock'; import LockIcon from '@mui/icons-material/Lock';
import PowerSettingsNewIcon from '@mui/icons-material/PowerSettingsNew';
import { import {
BlockFormControlLabel, BlockFormControlLabel,
@@ -25,11 +27,13 @@ import {
FormLoader, FormLoader,
SectionContent, SectionContent,
ValidatedPasswordField, ValidatedPasswordField,
ValidatedTextField ValidatedTextField,
MessageBox
} from '../../components'; } from '../../components';
import { NetworkSettings } from '../../types'; import { NetworkSettings } from '../../types';
import * as NetworkApi from '../../api/network'; import * as NetworkApi from '../../api/network';
import { numberValue, updateValue, useRest } from '../../utils'; import { numberValue, updateValue, useRest } from '../../utils';
import * as EMSESP from '../../project/api';
import { WiFiConnectionContext } from './WiFiConnectionContext'; import { WiFiConnectionContext } from './WiFiConnectionContext';
import { isNetworkOpen, networkSecurityMode } from './WiFiNetworkSelector'; import { isNetworkOpen, networkSecurityMode } from './WiFiNetworkSelector';
@@ -38,14 +42,17 @@ import { validate } from '../../validators';
import { createNetworkSettingsValidator } from '../../validators/network'; import { createNetworkSettingsValidator } from '../../validators/network';
import { useI18nContext } from '../../i18n/i18n-react'; import { useI18nContext } from '../../i18n/i18n-react';
import RestartMonitor from '../system/RestartMonitor';
const WiFiSettingsForm: FC = () => { const WiFiSettingsForm: FC = () => {
const { LL } = useI18nContext(); const { LL } = useI18nContext();
const { enqueueSnackbar } = useSnackbar();
const { selectedNetwork, deselectNetwork } = useContext(WiFiConnectionContext); const { selectedNetwork, deselectNetwork } = useContext(WiFiConnectionContext);
const [initialized, setInitialized] = useState(false); 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, read: NetworkApi.readNetworkSettings,
update: NetworkApi.updateNetworkSettings update: NetworkApi.updateNetworkSettings
}); });
@@ -62,7 +69,9 @@ const WiFiSettingsForm: FC = () => {
bandwidth20: false, bandwidth20: false,
tx_power: 20, tx_power: 20,
nosleep: false, nosleep: false,
enableMDNS: true enableMDNS: true,
enableCORS: false,
CORSOrigin: '*'
}); });
} }
setInitialized(true); 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 ( return (
<> <>
<Typography sx={{ pt: 2 }} variant="h6" color="primary"> <Typography sx={{ pt: 2 }} variant="h6" color="primary">
@@ -162,11 +180,6 @@ const WiFiSettingsForm: FC = () => {
label={LL.NETWORK_LOW_BAND()} 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"> <Typography sx={{ pt: 2 }} variant="h6" color="primary">
{LL.GENERAL_OPTIONS()} {LL.GENERAL_OPTIONS()}
</Typography> </Typography>
@@ -182,6 +195,28 @@ const WiFiSettingsForm: FC = () => {
margin="normal" 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 <BlockFormControlLabel
control={<Checkbox name="enableIPv6" checked={data.enableIPv6} onChange={updateFormValue} />} control={<Checkbox name="enableIPv6" checked={data.enableIPv6} onChange={updateFormValue} />}
label={LL.NETWORK_ENABLE_IPV6()} 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> <ButtonRow>
<Button <Button
startIcon={<SaveIcon />} startIcon={<SaveIcon />}
@@ -257,13 +300,14 @@ const WiFiSettingsForm: FC = () => {
{LL.SAVE()} {LL.SAVE()}
</Button> </Button>
</ButtonRow> </ButtonRow>
)}
</> </>
); );
}; };
return ( return (
<SectionContent title={LL.SETTINGS_OF(LL.NETWORK(1))} titleGutter> <SectionContent title={LL.SETTINGS_OF(LL.NETWORK(1))} titleGutter>
{content()} {restarting ? <RestartMonitor /> : content()}
</SectionContent> </SectionContent>
); );
}; };

View File

@@ -3,6 +3,7 @@ import type { Translation } from '../i18n-types';
/* eslint-disable */ /* eslint-disable */
const de: Translation = { const de: Translation = {
// ...en as Translation,
LANGUAGE: 'Sprache', LANGUAGE: 'Sprache',
RETRY: 'Neuer Versuch', RETRY: 'Neuer Versuch',
LOADING: 'Laden', LOADING: 'Laden',
@@ -190,8 +191,8 @@ const de: Translation = {
SYSTEM_FACTORY_TEXT_DIALOG: 'Sind Sie sicher alle Einstellungen auf Werkseinstellung zu setzen?', SYSTEM_FACTORY_TEXT_DIALOG: 'Sind Sie sicher alle Einstellungen auf Werkseinstellung zu setzen?',
VERSION_CHECK: 'Versionsprüfung', VERSION_CHECK: 'Versionsprüfung',
THE_LATEST: 'Die neueste', THE_LATEST: 'Die neueste',
OFFICIAL: 'official', OFFICIAL: 'offizielle',
DEVELOPMENT: 'development', DEVELOPMENT: 'Entwicklungs',
VERSION_IS: 'Version ist', VERSION_IS: 'Version ist',
RELEASE_NOTES: 'Versionshinweise', RELEASE_NOTES: 'Versionshinweise',
EMS_ESP_VER: 'EMS-ESP Version', EMS_ESP_VER: 'EMS-ESP Version',
@@ -245,9 +246,10 @@ const de: Translation = {
MQTT_INT_THERMOSTATS: 'Thermostate', MQTT_INT_THERMOSTATS: 'Thermostate',
MQTT_INT_SOLAR: 'Solarmodule', MQTT_INT_SOLAR: 'Solarmodule',
MQTT_INT_MIXER: 'Mischermodule', MQTT_INT_MIXER: 'Mischermodule',
MQTT_INT_HEARTBEAT: 'Heartbeat',
MQTT_QUEUE: 'MQTT Queue', MQTT_QUEUE: 'MQTT Queue',
DEFAULT: 'Standard', 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_CLEAN_SESSION: 'Setze `Clean Session`',
MQTT_RETAIN_FLAG: 'Setze `Retain flag` immer', MQTT_RETAIN_FLAG: 'Setze `Retain flag` immer',
INACTIVE: 'Inaktiv', INACTIVE: 'Inaktiv',
@@ -283,6 +285,8 @@ const de: Translation = {
NETWORK_DISABLE_SLEEP: 'Deaktiviere WiFi Schlafmodus', NETWORK_DISABLE_SLEEP: 'Deaktiviere WiFi Schlafmodus',
NETWORK_LOW_BAND: 'Verwende niedrige WiFi Bandbreite', NETWORK_LOW_BAND: 'Verwende niedrige WiFi Bandbreite',
NETWORK_USE_DNS: 'Aktiviere mDNS Service', NETWORK_USE_DNS: 'Aktiviere mDNS Service',
NETWORK_ENABLE_CORS: 'Aktiviere CORS',
NETWORK_CORS_ORIGIN: 'CORS origin',
NETWORK_ENABLE_IPV6: 'Aktiviere IPv6 Unterstützung', NETWORK_ENABLE_IPV6: 'Aktiviere IPv6 Unterstützung',
NETWORK_FIXED_IP: 'Feste IP Adresse', NETWORK_FIXED_IP: 'Feste IP Adresse',
NETWORK_GATEWAY: 'Gateway', NETWORK_GATEWAY: 'Gateway',

View File

@@ -245,6 +245,7 @@ const en: Translation = {
MQTT_INT_THERMOSTATS: 'Thermostats', MQTT_INT_THERMOSTATS: 'Thermostats',
MQTT_INT_SOLAR: 'Solar Modules', MQTT_INT_SOLAR: 'Solar Modules',
MQTT_INT_MIXER: 'Mixer Modules', MQTT_INT_MIXER: 'Mixer Modules',
MQTT_INT_HEARTBEAT: 'Heartbeat',
MQTT_QUEUE: 'MQTT Queue', MQTT_QUEUE: 'MQTT Queue',
DEFAULT: 'Default', DEFAULT: 'Default',
MQTT_MULTIPLE_INSTANCES: 'Enable Multiple Instances of EMS-ESP', MQTT_MULTIPLE_INSTANCES: 'Enable Multiple Instances of EMS-ESP',
@@ -283,6 +284,8 @@ const en: Translation = {
NETWORK_DISABLE_SLEEP: 'Disable WiFi Sleep Mode', NETWORK_DISABLE_SLEEP: 'Disable WiFi Sleep Mode',
NETWORK_LOW_BAND: 'Use Lower WiFi Bandwidth', NETWORK_LOW_BAND: 'Use Lower WiFi Bandwidth',
NETWORK_USE_DNS: 'Enable mDNS Service', NETWORK_USE_DNS: 'Enable mDNS Service',
NETWORK_ENABLE_CORS: 'Enable CORS',
NETWORK_CORS_ORIGIN: 'CORS origin',
NETWORK_ENABLE_IPV6: 'Enable IPv6 support', NETWORK_ENABLE_IPV6: 'Enable IPv6 support',
NETWORK_FIXED_IP: 'Use Fixed IP address', NETWORK_FIXED_IP: 'Use Fixed IP address',
NETWORK_GATEWAY: 'Gateway', NETWORK_GATEWAY: 'Gateway',

View File

@@ -245,6 +245,7 @@ const nl: Translation = {
MQTT_INT_THERMOSTATS: 'Thermostaten', MQTT_INT_THERMOSTATS: 'Thermostaten',
MQTT_INT_SOLAR: 'Solar Modules', MQTT_INT_SOLAR: 'Solar Modules',
MQTT_INT_MIXER: 'Mixer Modules', MQTT_INT_MIXER: 'Mixer Modules',
MQTT_INT_HEARTBEAT: 'Heartbeat',
MQTT_QUEUE: 'MQTT Queue', MQTT_QUEUE: 'MQTT Queue',
DEFAULT: 'Default', DEFAULT: 'Default',
MQTT_MULTIPLE_INSTANCES: 'Enable Multiple Instances of EMS-ESP', MQTT_MULTIPLE_INSTANCES: 'Enable Multiple Instances of EMS-ESP',
@@ -283,6 +284,8 @@ const nl: Translation = {
NETWORK_DISABLE_SLEEP: 'WiFi Sleep Mode uitzetten', NETWORK_DISABLE_SLEEP: 'WiFi Sleep Mode uitzetten',
NETWORK_LOW_BAND: 'Lagere WiFi bandbreedte gebruiken', NETWORK_LOW_BAND: 'Lagere WiFi bandbreedte gebruiken',
NETWORK_USE_DNS: 'Activeer mDNS Service', NETWORK_USE_DNS: 'Activeer mDNS Service',
NETWORK_ENABLE_CORS: 'Activeer CORS',
NETWORK_CORS_ORIGIN: 'CORS origin',
NETWORK_ENABLE_IPV6: 'Activeer IPv6 support', NETWORK_ENABLE_IPV6: 'Activeer IPv6 support',
NETWORK_FIXED_IP: 'Gebruik vast IP addres', NETWORK_FIXED_IP: 'Gebruik vast IP addres',
NETWORK_GATEWAY: 'Gateway', NETWORK_GATEWAY: 'Gateway',

View File

@@ -245,6 +245,7 @@ const no: Translation = {
MQTT_INT_THERMOSTATS: 'Termostat', MQTT_INT_THERMOSTATS: 'Termostat',
MQTT_INT_SOLAR: 'Solpaneler', MQTT_INT_SOLAR: 'Solpaneler',
MQTT_INT_MIXER: 'Blandeventil', MQTT_INT_MIXER: 'Blandeventil',
MQTT_INT_HEARTBEAT: 'Heartbeat',
MQTT_QUEUE: 'MQTT Queue', MQTT_QUEUE: 'MQTT Queue',
DEFAULT: 'Standard', DEFAULT: 'Standard',
MQTT_MULTIPLE_INSTANCES: 'Enable Multiple Instances of EMS-ESP', 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_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_LOW_BAND: 'Benytt smalere båndbredde på trådløst nettverk',
NETWORK_USE_DNS: 'Aktiviser mDNS Service', NETWORK_USE_DNS: 'Aktiviser mDNS Service',
NETWORK_ENABLE_CORS: 'Aktiviser CORS',
NETWORK_CORS_ORIGIN: 'CORS origin',
NETWORK_ENABLE_IPV6: 'Aktiviser IPv6 støtte', NETWORK_ENABLE_IPV6: 'Aktiviser IPv6 støtte',
NETWORK_FIXED_IP: 'Benytt statisk IP adresse', NETWORK_FIXED_IP: 'Benytt statisk IP adresse',
NETWORK_GATEWAY: 'Gateway', NETWORK_GATEWAY: 'Gateway',

View File

@@ -245,6 +245,7 @@ const pl: BaseTranslation = {
MQTT_INT_THERMOSTATS: 'Termostaty', MQTT_INT_THERMOSTATS: 'Termostaty',
MQTT_INT_SOLAR: 'Panele solarne', MQTT_INT_SOLAR: 'Panele solarne',
MQTT_INT_MIXER: 'Mieszacze', MQTT_INT_MIXER: 'Mieszacze',
MQTT_INT_HEARTBEAT: 'Heartbeat',
MQTT_QUEUE: 'Kolejka MQTT', MQTT_QUEUE: 'Kolejka MQTT',
DEFAULT: '{{Pozostałe|Domyślna|}}', DEFAULT: '{{Pozostałe|Domyślna|}}',
MQTT_MULTIPLE_INSTANCES: 'Enable Multiple Instances of EMS-ESP', 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_DISABLE_SLEEP: 'Wyłącz tryb usypiania WiFi',
NETWORK_LOW_BAND: 'Używaj zmniejszonej przepustowości WiFi', NETWORK_LOW_BAND: 'Używaj zmniejszonej przepustowości WiFi',
NETWORK_USE_DNS: 'Włącz wsparcie dla mDNS', 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_ENABLE_IPV6: 'Włącz wsparcie dla IPv6',
NETWORK_FIXED_IP: 'Użyj stałego adresu IP', NETWORK_FIXED_IP: 'Użyj stałego adresu IP',
NETWORK_GATEWAY: 'Brama', NETWORK_GATEWAY: 'Brama',

View File

@@ -245,6 +245,7 @@ const se: Translation = {
MQTT_INT_THERMOSTATS: 'Termostater', MQTT_INT_THERMOSTATS: 'Termostater',
MQTT_INT_SOLAR: 'Solpaneler', MQTT_INT_SOLAR: 'Solpaneler',
MQTT_INT_MIXER: 'Blandarventiler', MQTT_INT_MIXER: 'Blandarventiler',
MQTT_INT_HEARTBEAT: 'Heartbeat',
MQTT_QUEUE: 'MQTT Queue', MQTT_QUEUE: 'MQTT Queue',
DEFAULT: 'Standard', DEFAULT: 'Standard',
MQTT_MULTIPLE_INSTANCES: 'Enable Multiple Instances of EMS-ESP', MQTT_MULTIPLE_INSTANCES: 'Enable Multiple Instances of EMS-ESP',
@@ -283,6 +284,8 @@ const se: Translation = {
NETWORK_DISABLE_SLEEP: 'Inaktivera sömnläge', NETWORK_DISABLE_SLEEP: 'Inaktivera sömnläge',
NETWORK_LOW_BAND: 'Använd lägre bandbredd', NETWORK_LOW_BAND: 'Använd lägre bandbredd',
NETWORK_USE_DNS: 'Aktivera mDNS-tjänsten', NETWORK_USE_DNS: 'Aktivera mDNS-tjänsten',
NETWORK_ENABLE_CORS: 'Aktivera CORS',
NETWORK_CORS_ORIGIN: 'CORS origin',
NETWORK_ENABLE_IPV6: 'Aktivera IPv6-support', NETWORK_ENABLE_IPV6: 'Aktivera IPv6-support',
NETWORK_FIXED_IP: 'Använd statiskt IP', NETWORK_FIXED_IP: 'Använd statiskt IP',
NETWORK_GATEWAY: 'Gateway', NETWORK_GATEWAY: 'Gateway',

View File

@@ -36,6 +36,7 @@ export interface MqttSettings {
publish_time_mixer: number; publish_time_mixer: number;
publish_time_other: number; publish_time_other: number;
publish_time_sensor: number; publish_time_sensor: number;
publish_time_heartbeat: number;
mqtt_qos: number; mqtt_qos: number;
mqtt_retain: boolean; mqtt_retain: boolean;
ha_enabled: boolean; ha_enabled: boolean;

View File

@@ -48,6 +48,8 @@ export interface NetworkSettings {
dns_ip_1?: string; dns_ip_1?: string;
dns_ip_2?: string; dns_ip_2?: string;
enableMDNS: boolean; enableMDNS: boolean;
enableCORS: boolean;
CORSOrigin: string;
} }
export interface WiFiNetworkList { export interface WiFiNetworkList {

View File

@@ -11,5 +11,9 @@ export const MQTT_SETTINGS_VALIDATOR = new Schema({
keep_alive: [ keep_alive: [
{ required: true, message: 'Keep alive is required' }, { required: true, message: 'Keep alive is required' },
{ type: 'number', min: 1, max: 86400, message: 'Keep alive must be between 1 and 86400' } { 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' }
] ]
}); });

View File

@@ -46,6 +46,13 @@ ESP8266React::ESP8266React(AsyncWebServer * server, FS * fs)
void ESP8266React::begin() { void ESP8266React::begin() {
_networkSettingsService.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(); _apSettingsService.begin();
_ntpSettingsService.begin(); _ntpSettingsService.begin();
_otaSettingsService.begin(); _otaSettingsService.begin();

View File

@@ -163,6 +163,7 @@ void MqttSettings::read(MqttSettings & settings, JsonObject & root) {
root["publish_time_mixer"] = settings.publish_time_mixer; root["publish_time_mixer"] = settings.publish_time_mixer;
root["publish_time_other"] = settings.publish_time_other; root["publish_time_other"] = settings.publish_time_other;
root["publish_time_sensor"] = settings.publish_time_sensor; root["publish_time_sensor"] = settings.publish_time_sensor;
root["publish_time_heartbeat"] = settings.publish_time_heartbeat;
root["mqtt_qos"] = settings.mqtt_qos; root["mqtt_qos"] = settings.mqtt_qos;
root["mqtt_retain"] = settings.mqtt_retain; root["mqtt_retain"] = settings.mqtt_retain;
root["ha_enabled"] = settings.ha_enabled; 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_mixer = root["publish_time_mixer"] | EMSESP_DEFAULT_PUBLISH_TIME;
newSettings.publish_time_other = root["publish_time_other"] | 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_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.ha_enabled = root["ha_enabled"] | EMSESP_DEFAULT_HA_ENABLED;
newSettings.nested_format = root["nested_format"] | EMSESP_DEFAULT_NESTED_FORMAT; newSettings.nested_format = root["nested_format"] | EMSESP_DEFAULT_NESTED_FORMAT;
@@ -285,6 +287,11 @@ StateUpdateResult MqttSettings::update(JsonObject & root, MqttSettings & setting
changed = true; 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) { if (changed) {
emsesp::EMSESP::mqtt_.reset_mqtt(); emsesp::EMSESP::mqtt_.reset_mqtt();
} }

View File

@@ -90,6 +90,7 @@ class MqttSettings {
uint16_t publish_time_mixer; uint16_t publish_time_mixer;
uint16_t publish_time_other; uint16_t publish_time_other;
uint16_t publish_time_sensor; uint16_t publish_time_sensor;
uint16_t publish_time_heartbeat;
uint8_t mqtt_qos; uint8_t mqtt_qos;
bool mqtt_retain; bool mqtt_retain;
bool ha_enabled; bool ha_enabled;

View File

@@ -39,6 +39,8 @@ class NetworkSettings {
int8_t tx_power; int8_t tx_power;
bool nosleep; bool nosleep;
bool enableMDNS; bool enableMDNS;
bool enableCORS;
String CORSOrigin;
// optional configuration for static IP address // optional configuration for static IP address
IPAddress localIP; IPAddress localIP;
@@ -58,6 +60,8 @@ class NetworkSettings {
root["tx_power"] = settings.tx_power; root["tx_power"] = settings.tx_power;
root["nosleep"] = settings.nosleep; root["nosleep"] = settings.nosleep;
root["enableMDNS"] = settings.enableMDNS; root["enableMDNS"] = settings.enableMDNS;
root["enableCORS"] = settings.enableCORS;
root["CORSOrigin"] = settings.CORSOrigin;
// extended settings // extended settings
JsonUtils::writeIP(root, "local_ip", settings.localIP); JsonUtils::writeIP(root, "local_ip", settings.localIP);
@@ -68,6 +72,8 @@ class NetworkSettings {
} }
static StateUpdateResult update(JsonObject & root, NetworkSettings & settings) { static StateUpdateResult update(JsonObject & root, NetworkSettings & settings) {
auto enableCORS = settings.enableCORS;
auto CORSOrigin = settings.CORSOrigin;
settings.ssid = root["ssid"] | FACTORY_WIFI_SSID; settings.ssid = root["ssid"] | FACTORY_WIFI_SSID;
settings.password = root["password"] | FACTORY_WIFI_PASSWORD; settings.password = root["password"] | FACTORY_WIFI_PASSWORD;
settings.hostname = root["hostname"] | FACTORY_WIFI_HOSTNAME; settings.hostname = root["hostname"] | FACTORY_WIFI_HOSTNAME;
@@ -77,6 +83,8 @@ class NetworkSettings {
settings.tx_power = root["tx_power"] | 20; settings.tx_power = root["tx_power"] | 20;
settings.nosleep = root["nosleep"] | false; settings.nosleep = root["nosleep"] | false;
settings.enableMDNS = root["enableMDNS"] | true; settings.enableMDNS = root["enableMDNS"] | true;
settings.enableCORS = root["enableCORS"] | false;
settings.CORSOrigin = root["CORSOrigin"] | "*";
// extended settings // extended settings
JsonUtils::readIP(root, "local_ip", settings.localIP); 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))) { if (settings.staticIPConfig && (IPUtils::isNotSet(settings.localIP) || IPUtils::isNotSet(settings.gatewayIP) || IPUtils::isNotSet(settings.subnetMask))) {
settings.staticIPConfig = false; settings.staticIPConfig = false;
} }
if (enableCORS != settings.enableCORS || CORSOrigin != settings.CORSOrigin) {
return StateUpdateResult::CHANGED_RESTART; // tell WebUI that a restart is needed
}
return StateUpdateResult::CHANGED; return StateUpdateResult::CHANGED;
} }

View File

@@ -89,6 +89,7 @@ class DummySettings {
uint16_t publish_time_mixer = 10; uint16_t publish_time_mixer = 10;
uint16_t publish_time_other = 10; uint16_t publish_time_other = 10;
uint16_t publish_time_sensor = 10; uint16_t publish_time_sensor = 10;
uint16_t publish_time_heartbeat = 60;
String hostname = "ems-esp"; String hostname = "ems-esp";
String jwtSecret = "ems-esp"; String jwtSecret = "ems-esp";
@@ -102,6 +103,8 @@ class DummySettings {
String dnsIP2 = ""; String dnsIP2 = "";
bool enableIPv6 = false; bool enableIPv6 = false;
bool enableMDNS = true; bool enableMDNS = true;
bool enableCORS = false;
String CORSOrigin = "*";
uint8_t phy_type = 0; uint8_t phy_type = 0;
uint8_t eth_power = 0; // 0 means -1 uint8_t eth_power = 0; // 0 means -1

View File

@@ -122,7 +122,11 @@ network_settings = {
hostname: 'ems-esp', hostname: 'ems-esp',
nosleep: true, nosleep: true,
tx_power: 20, tx_power: 20,
bandwidth20: false,
static_ip_config: false, static_ip_config: false,
enableMDNS: true,
enableCORS: false,
CORSOrigin: '*',
} }
const network_status = { const network_status = {
status: 3, status: 3,
@@ -226,6 +230,7 @@ mqtt_settings = {
publish_time_mixer: 10, publish_time_mixer: 10,
publish_time_other: 10, publish_time_other: 10,
publish_time_sensor: 10, publish_time_sensor: 10,
publish_time_heartbeat: 60,
mqtt_qos: 0, mqtt_qos: 0,
mqtt_retain: false, mqtt_retain: false,
ha_enabled: true, ha_enabled: true,

View File

@@ -296,7 +296,7 @@ void AnalogSensor::loop() {
} }
// update analog information name and offset // 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 boolean found_sensor = false; // see if we can find the sensor in our customization list
EMSESP::webCustomizationService.update( 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()); snprintf(topic, sizeof(topic), "%s%s/%s", F_(analogsensor), "_data", sensor.name().c_str());
} }
char payload[10]; 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_0:
case AnalogType::PWM_1: case AnalogType::PWM_1:
case AnalogType::PWM_2: 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; break;
default: default:
dataSensor["value"] = (uint8_t)sensor.value(); // convert to char for 1 or 0 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 // 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) : gpio_(gpio)
, name_(name) , name_(name)
, offset_(offset) , offset_(offset)

View File

@@ -35,10 +35,10 @@ class AnalogSensor {
public: public:
class Sensor { class Sensor {
public: 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; ~Sensor() = default;
void set_offset(const float offset) { void set_offset(const double offset) {
offset_ = offset; offset_ = offset;
} }
@@ -52,23 +52,23 @@ class AnalogSensor {
return gpio_; return gpio_;
} }
float value() const { double value() const {
return value_; return value_;
} }
void set_value(float value) { void set_value(const double value) {
value_ = value; value_ = value;
} }
float factor() const { double factor() const {
return factor_; return factor_;
} }
void set_factor(float factor) { void set_factor(const double factor) {
factor_ = factor; factor_ = factor;
} }
float offset() const { double offset() const {
return offset_; return offset_;
} }
@@ -84,7 +84,7 @@ class AnalogSensor {
return type_; return type_;
} }
void set_type(int8_t type) { void set_type(const int8_t type) {
type_ = type; type_ = type;
} }
@@ -101,10 +101,10 @@ class AnalogSensor {
private: private:
uint8_t gpio_; uint8_t gpio_;
std::string name_; std::string name_;
float offset_; double offset_;
float factor_; double factor_;
uint8_t uom_; 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_; int8_t type_;
}; };
@@ -157,7 +157,7 @@ class AnalogSensor {
return sensors_.size(); 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; bool get_value_info(JsonObject & output, const char * cmd, const int8_t id) const;
#ifdef EMSESP_DEBUG #ifdef EMSESP_DEBUG

View File

@@ -157,6 +157,10 @@
#define EMSESP_DEFAULT_PUBLISH_TIME 10 #define EMSESP_DEFAULT_PUBLISH_TIME 10
#endif #endif
#ifndef EMSESP_DEFAULT_PUBLISH_HEARTBEAT
#define EMSESP_DEFAULT_PUBLISH_HEARTBEAT 60
#endif
#ifndef EMSESP_DEFAULT_NESTED_FORMAT #ifndef EMSESP_DEFAULT_NESTED_FORMAT
#define EMSESP_DEFAULT_NESTED_FORMAT 1 #define EMSESP_DEFAULT_NESTED_FORMAT 1
#endif #endif

View File

@@ -244,7 +244,7 @@ char * Helpers::render_value(char * result, uint8_t value, int8_t format, const
// float: convert float to char // float: convert float to char
// format is the precision, 0 to 8 // 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) { if (format > 8) {
return nullptr; return nullptr;
} }

View File

@@ -27,7 +27,7 @@ namespace emsesp {
class Helpers { class Helpers {
public: 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 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 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); static char * render_value(char * result, const uint16_t value, const int8_t format, const uint8_t fahrenheit = 0);

View File

@@ -36,6 +36,7 @@ uint32_t Mqtt::publish_time_solar_;
uint32_t Mqtt::publish_time_mixer_; uint32_t Mqtt::publish_time_mixer_;
uint32_t Mqtt::publish_time_sensor_; uint32_t Mqtt::publish_time_sensor_;
uint32_t Mqtt::publish_time_other_; uint32_t Mqtt::publish_time_other_;
uint32_t Mqtt::publish_time_heartbeat_;
bool Mqtt::mqtt_enabled_; bool Mqtt::mqtt_enabled_;
bool Mqtt::multiple_instances_; bool Mqtt::multiple_instances_;
bool Mqtt::ha_enabled_; bool Mqtt::ha_enabled_;
@@ -147,6 +148,12 @@ void Mqtt::loop() {
process_queue(); 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 // dallas publish on change
if (!publish_time_sensor_) { if (!publish_time_sensor_) {
EMSESP::publish_sensor_values(false); EMSESP::publish_sensor_values(false);
@@ -432,6 +439,7 @@ void Mqtt::load_settings() {
publish_time_mixer_ = mqttSettings.publish_time_mixer * 1000; publish_time_mixer_ = mqttSettings.publish_time_mixer * 1000;
publish_time_other_ = mqttSettings.publish_time_other * 1000; publish_time_other_ = mqttSettings.publish_time_other * 1000;
publish_time_sensor_ = mqttSettings.publish_time_sensor * 1000; publish_time_sensor_ = mqttSettings.publish_time_sensor * 1000;
publish_time_heartbeat_ = mqttSettings.publish_time_heartbeat * 1000;
}); });
// create basename from base // 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 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) { bool Mqtt::get_publish_onchange(uint8_t device_type) {
if (publish_single_ && !ha_enabled_) { if (publish_single_ && !ha_enabled_) {
return false; return false;
@@ -653,7 +665,7 @@ std::shared_ptr<const MqttMessage> Mqtt::queue_message(const uint8_t operation,
std::shared_ptr<MqttMessage> message; std::shared_ptr<MqttMessage> message;
message = std::make_shared<MqttMessage>(operation, topic, payload, retain); message = std::make_shared<MqttMessage>(operation, topic, payload, retain);
#ifdef EMSESP_DEBUG #if defined(EMSESP_DEBUG)
if (operation == Operation::PUBLISH) { if (operation == Operation::PUBLISH) {
if (message->payload.empty()) { if (message->payload.empty()) {
LOG_INFO("[DEBUG] Adding to queue: (Publish) topic='%s' empty payload", message->topic.c_str()); 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, mqtt_message.retry_count_ + 1,
message->payload.size(), message->payload.size(),
packet_id); packet_id);
#if defined(EMSESP_DEBUG)
LOG_DEBUG("Payload:%s", message->payload.c_str()); // extra message for #784
#endif
if (packet_id == 0) { if (packet_id == 0) {
// it failed. if we retried n times, give up. remove from queue // it failed. if we retried n times, give up. remove from queue
if (mqtt_message.retry_count_ == (MQTT_PUBLISH_MAX_RETRY - 1)) { if (mqtt_message.retry_count_ == (MQTT_PUBLISH_MAX_RETRY - 1)) {

View File

@@ -65,6 +65,7 @@ class Mqtt {
void set_publish_time_mixer(uint16_t publish_time); void set_publish_time_mixer(uint16_t publish_time);
void set_publish_time_other(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_sensor(uint16_t publish_time);
void set_publish_time_heartbeat(uint16_t publish_time);
bool get_publish_onchange(uint8_t device_type); bool get_publish_onchange(uint8_t device_type);
enum Operation : uint8_t { PUBLISH, SUBSCRIBE, UNSUBSCRIBE }; enum Operation : uint8_t { PUBLISH, SUBSCRIBE, UNSUBSCRIBE };
@@ -292,6 +293,7 @@ class Mqtt {
uint32_t last_publish_mixer_ = 0; uint32_t last_publish_mixer_ = 0;
uint32_t last_publish_other_ = 0; uint32_t last_publish_other_ = 0;
uint32_t last_publish_sensor_ = 0; uint32_t last_publish_sensor_ = 0;
uint32_t last_publish_heartbeat_ = 0;
uint32_t last_publish_queue_ = 0; uint32_t last_publish_queue_ = 0;
static bool connecting_; static bool connecting_;
@@ -315,6 +317,7 @@ class Mqtt {
static uint32_t publish_time_mixer_; static uint32_t publish_time_mixer_;
static uint32_t publish_time_other_; static uint32_t publish_time_other_;
static uint32_t publish_time_sensor_; static uint32_t publish_time_sensor_;
static uint32_t publish_time_heartbeat_;
static bool mqtt_enabled_; static bool mqtt_enabled_;
static bool ha_enabled_; static bool ha_enabled_;
static uint8_t nested_format_; static uint8_t nested_format_;

View File

@@ -512,12 +512,6 @@ void System::loop() {
led_monitor(); // check status and report back using the LED led_monitor(); // check status and report back using the LED
system_check(); // check system health 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 #ifndef EMSESP_STANDALONE
#if defined(EMSESP_DEBUG) #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["enable IPv6"] = settings.enableIPv6;
node["low bandwidth"] = settings.bandwidth20; node["low bandwidth"] = settings.bandwidth20;
node["disable sleep"] = settings.nosleep; 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 #ifndef EMSESP_STANDALONE
EMSESP::esp8266React.getAPSettingsService()->read([&](APSettings & settings) { 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["ha enabled"] = settings.ha_enabled;
node["mqtt qos"] = settings.mqtt_qos; node["mqtt qos"] = settings.mqtt_qos;
node["mqtt retain"] = settings.mqtt_retain; 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 boiler"] = settings.publish_time_boiler;
node["publish time thermostat"] = settings.publish_time_thermostat; node["publish time thermostat"] = settings.publish_time_thermostat;
node["publish time solar"] = settings.publish_time_solar; node["publish time solar"] = settings.publish_time_solar;

View File

@@ -250,7 +250,6 @@ class System {
static constexpr uint32_t HEALTHCHECK_LED_FLASH_DUARATION = 150; 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_BUS = (1 << 0); // 1
static constexpr uint8_t HEALTHCHECK_NO_NETWORK = (1 << 1); // 2 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 static constexpr uint8_t LED_ON = HIGH; // LED on
#ifndef EMSESP_STANDALONE #ifndef EMSESP_STANDALONE
@@ -263,7 +262,6 @@ class System {
int8_t wifi_quality(int8_t dBm); 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 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; uint32_t last_system_check_ = 0;
bool upload_status_ = false; // true if we're in the middle of a OTA firmware upload bool upload_status_ = false; // true if we're in the middle of a OTA firmware upload

View File

@@ -44,8 +44,8 @@ class AnalogCustomization {
public: public:
uint8_t gpio; uint8_t gpio;
std::string name; std::string name;
float offset; double offset;
float factor; double factor;
uint8_t uom; // 0 is none uint8_t uom; // 0 is none
int8_t type; // -1 is for deletion int8_t type; // -1 is for deletion

View File

@@ -284,8 +284,8 @@ void WebDataService::write_analog(AsyncWebServerRequest * request, JsonVariant &
uint8_t gpio = analog["gpio"]; // this is the unique key, the GPIO uint8_t gpio = analog["gpio"]; // this is the unique key, the GPIO
std::string name = analog["name"]; std::string name = analog["name"];
float factor = analog["factor"]; double factor = analog["factor"];
float offset = analog["offset"]; double offset = analog["offset"];
uint8_t uom = analog["uom"]; uint8_t uom = analog["uom"];
int8_t type = analog["type"]; int8_t type = analog["type"];
ok = EMSESP::analogsensor_.update(gpio, name, offset, factor, uom, type); ok = EMSESP::analogsensor_.update(gpio, name, offset, factor, uom, type);