mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-06 15:59:52 +03:00
feat: board profiles (#11)
This commit is contained in:
@@ -46,6 +46,6 @@
|
|||||||
- new ESP32 partition side to allow for smoother OTA and fallback
|
- new ESP32 partition side to allow for smoother OTA and fallback
|
||||||
- network Gateway IP is optional (#682)emsesp/EMS-ESP
|
- network Gateway IP is optional (#682)emsesp/EMS-ESP
|
||||||
- moved to a new GitHub repo https://github.com/emsesp/EMS-ESP32
|
- moved to a new GitHub repo https://github.com/emsesp/EMS-ESP32
|
||||||
|
- Invert LED changed to Hide LED
|
||||||
### Removed
|
### Removed
|
||||||
- Shower Alert (disabled for now)
|
- Shower Alert (disabled for now)
|
||||||
|
|||||||
23
interface/src/project/EMSESPBoardProfiles.tsx
Normal file
23
interface/src/project/EMSESPBoardProfiles.tsx
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import MenuItem from '@material-ui/core/MenuItem';
|
||||||
|
|
||||||
|
type BoardProfiles = {
|
||||||
|
[name: string]: string
|
||||||
|
};
|
||||||
|
|
||||||
|
export const BOARD_PROFILES: BoardProfiles = {
|
||||||
|
"S32": "Gateway S32",
|
||||||
|
"NODEMCU": "NodeMCU 32S",
|
||||||
|
"MT-ET": "MT-ET Live D1 Mini",
|
||||||
|
"LOLIN": "Lolin D32",
|
||||||
|
"WEMOS": "Wemos Mini D1-32",
|
||||||
|
"E32": "Gateway E32",
|
||||||
|
"OLIMEX": "Olimex ESP32-EVB-EA",
|
||||||
|
"TLK110": "Ethernet (TLK110)"
|
||||||
|
}
|
||||||
|
|
||||||
|
export function boardProfileSelectItems() {
|
||||||
|
return Object.keys(BOARD_PROFILES).map(code => (
|
||||||
|
<MenuItem key={code} value={code}>{BOARD_PROFILES[code]}</MenuItem>
|
||||||
|
));
|
||||||
|
}
|
||||||
@@ -7,27 +7,88 @@ import MenuItem from '@material-ui/core/MenuItem';
|
|||||||
|
|
||||||
import Grid from '@material-ui/core/Grid';
|
import Grid from '@material-ui/core/Grid';
|
||||||
|
|
||||||
|
import { redirectingAuthorizedFetch, withAuthenticatedContext, AuthenticatedContextProps } from "../authentication";
|
||||||
|
|
||||||
import { RestFormProps, FormActions, FormButton, BlockFormControlLabel } from '../components';
|
import { RestFormProps, FormActions, FormButton, BlockFormControlLabel } from '../components';
|
||||||
|
|
||||||
import { isIP, optional } from '../validators';
|
import { isIP, optional } from '../validators';
|
||||||
|
|
||||||
import { EMSESPSettings } from './EMSESPtypes';
|
import { EMSESPSettings } from './EMSESPtypes';
|
||||||
|
|
||||||
type EMSESPSettingsFormProps = RestFormProps<EMSESPSettings> & WithWidthProps;
|
import { boardProfileSelectItems } from './EMSESPBoardProfiles';
|
||||||
|
|
||||||
|
import { ENDPOINT_ROOT } from "../api";
|
||||||
|
export const BOARD_PROFILE_ENDPOINT = ENDPOINT_ROOT + "boardProfile";
|
||||||
|
|
||||||
|
type EMSESPSettingsFormProps = RestFormProps<EMSESPSettings> & AuthenticatedContextProps & WithWidthProps;
|
||||||
|
|
||||||
|
interface EMSESPSettingsFormState {
|
||||||
|
processing: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
class EMSESPSettingsForm extends React.Component<EMSESPSettingsFormProps> {
|
class EMSESPSettingsForm extends React.Component<EMSESPSettingsFormProps> {
|
||||||
|
|
||||||
|
state: EMSESPSettingsFormState = {
|
||||||
|
processing: false
|
||||||
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
ValidatorForm.addValidationRule('isOptionalIP', optional(isIP));
|
ValidatorForm.addValidationRule('isOptionalIP', optional(isIP));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
changeBoardProfile = (event: React.ChangeEvent<HTMLSelectElement>) => {
|
||||||
|
const { data, setData } = this.props;
|
||||||
|
setData({
|
||||||
|
...data,
|
||||||
|
board_profile: event.target.value
|
||||||
|
});
|
||||||
|
|
||||||
|
if (event.target.value === "CUSTOM")
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.setState({ processing: true });
|
||||||
|
redirectingAuthorizedFetch(BOARD_PROFILE_ENDPOINT, {
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify({ code: event.target.value }),
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
if (response.status === 200) {
|
||||||
|
return response.json();
|
||||||
|
}
|
||||||
|
throw Error("Unexpected response code: " + response.status);
|
||||||
|
})
|
||||||
|
.then((json) => {
|
||||||
|
this.props.enqueueSnackbar("Profile loaded", { variant: 'success' });
|
||||||
|
setData({
|
||||||
|
...data,
|
||||||
|
led_gpio: json.led_gpio,
|
||||||
|
dallas_gpio: json.dallas_gpio,
|
||||||
|
rx_gpio: json.rx_gpio,
|
||||||
|
tx_gpio: json.tx_gpio,
|
||||||
|
pbutton_gpio: json.pbutton_gpio,
|
||||||
|
board_profile: event.target.value
|
||||||
|
});
|
||||||
|
this.setState({ processing: false });
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
this.props.enqueueSnackbar(
|
||||||
|
error.message || "Problem fetching board profile",
|
||||||
|
{ variant: "warning" }
|
||||||
|
);
|
||||||
|
this.setState({ processing: false });
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { data, saveData, handleValueChange } = this.props;
|
const { data, saveData, handleValueChange } = this.props;
|
||||||
return (
|
return (
|
||||||
<ValidatorForm onSubmit={saveData}>
|
<ValidatorForm onSubmit={saveData}>
|
||||||
<Box bgcolor="info.main" p={2} mt={2} mb={2}>
|
<Box bgcolor="info.main" p={2} mt={2} mb={2}>
|
||||||
<Typography variant="body1">
|
<Typography variant="body1">
|
||||||
Modify any of the EMS-ESP settings here. For help visit the <Link target="_blank" href="https://emsesp.github.io/docs/#/Configure-firmware32?id=ems-esp-settings" color="primary">{'wiki'}</Link>.
|
Modify any of the EMS-ESP settings here. For help refer to the <Link target="_blank" href="https://emsesp.github.io/docs/#/Configure-firmware32?id=ems-esp-settings" color="primary">{'online documentation'}</Link>.
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
@@ -37,7 +98,6 @@ class EMSESPSettingsForm extends React.Component<EMSESPSettingsFormProps> {
|
|||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<Grid container spacing={1} direction="row" justify="flex-start" alignItems="flex-start">
|
<Grid container spacing={1} direction="row" justify="flex-start" alignItems="flex-start">
|
||||||
|
|
||||||
<Grid item xs={5}>
|
<Grid item xs={5}>
|
||||||
<SelectValidator name="tx_mode"
|
<SelectValidator name="tx_mode"
|
||||||
label="Tx Mode"
|
label="Tx Mode"
|
||||||
@@ -91,7 +151,7 @@ class EMSESPSettingsForm extends React.Component<EMSESPSettingsFormProps> {
|
|||||||
|
|
||||||
<Box color="warning.main" p={0} mt={0} mb={0}>
|
<Box color="warning.main" p={0} mt={0} mb={0}>
|
||||||
<Typography variant="body2">
|
<Typography variant="body2">
|
||||||
<i>Choose from a pre-configured board layout to automatically set the GPIO pins</i>
|
<i>Select a pre-configured board layout to automatically set the GPIO pins, or set your own custom configuration</i>
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
@@ -100,25 +160,18 @@ class EMSESPSettingsForm extends React.Component<EMSESPSettingsFormProps> {
|
|||||||
value={data.board_profile}
|
value={data.board_profile}
|
||||||
fullWidth
|
fullWidth
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
onChange={handleValueChange('board_profile')}
|
onChange={this.changeBoardProfile}
|
||||||
margin="normal">
|
margin="normal">
|
||||||
<MenuItem value={1}>Gateway S32</MenuItem>
|
{boardProfileSelectItems()}
|
||||||
<MenuItem value={2}>NodeMCU 32S</MenuItem>
|
<MenuItem key={"CUSTOM"} value={"CUSTOM"}>Custom...</MenuItem>
|
||||||
<MenuItem value={3}>Lolin D32</MenuItem>
|
|
||||||
<MenuItem value={4}>Wemos Mini D1-32</MenuItem>
|
|
||||||
<MenuItem value={10}>Gateway E32 (LAN8720)</MenuItem>
|
|
||||||
<MenuItem value={11}>Olimex ESP32-EVB-EA (LAN8720)</MenuItem>
|
|
||||||
<MenuItem value={12}>Ethernet (TLK110)</MenuItem>
|
|
||||||
<MenuItem value={0}>Custom...</MenuItem>
|
|
||||||
</SelectValidator>
|
</SelectValidator>
|
||||||
|
|
||||||
{ (data.board_profile === 0) &&
|
{ (data.board_profile === "CUSTOM") &&
|
||||||
|
|
||||||
<Grid container spacing={1} direction="row" justify="flex-start" alignItems="flex-start">
|
<Grid container spacing={1} direction="row" justify="flex-start" alignItems="flex-start">
|
||||||
<Grid item xs={4}>
|
<Grid item xs={4}>
|
||||||
<TextValidator
|
<TextValidator
|
||||||
validators={['required', 'isNumber', 'minNumber:0', 'maxNumber:40']}
|
validators={['required', 'isNumber', 'minNumber:0', 'maxNumber:40', 'matchRegexp:^((?!6|7|8|9|10|11|12|14|15|20|24|28|29|30|31)[0-9]*)$']}
|
||||||
errorMessages={['Rx GPIO is required', "Must be a number", "Must be 0 or higher", "Max value is 40"]}
|
errorMessages={['GPIO is required', "Must be a number", "Must be 0 or higher", "Max value is 40", "Not a valid GPIO"]}
|
||||||
name="rx_gpio"
|
name="rx_gpio"
|
||||||
label="Rx GPIO"
|
label="Rx GPIO"
|
||||||
fullWidth
|
fullWidth
|
||||||
@@ -131,8 +184,8 @@ class EMSESPSettingsForm extends React.Component<EMSESPSettingsFormProps> {
|
|||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={4}>
|
<Grid item xs={4}>
|
||||||
<TextValidator
|
<TextValidator
|
||||||
validators={['required', 'isNumber', 'minNumber:0', 'maxNumber:40']}
|
validators={['required', 'isNumber', 'minNumber:0', 'maxNumber:40', 'matchRegexp:^((?!6|7|8|9|10|11|12|14|15|20|24|28|29|30|31)[0-9]*)$']}
|
||||||
errorMessages={['Tx GPIO is required', "Must be a number", "Must be 0 or higher", "Max value is 40"]}
|
errorMessages={['GPIO is required', "Must be a number", "Must be 0 or higher", "Max value is 40", "Not a valid GPIO"]}
|
||||||
name="tx_gpio"
|
name="tx_gpio"
|
||||||
label="Tx GPIO"
|
label="Tx GPIO"
|
||||||
fullWidth
|
fullWidth
|
||||||
@@ -145,8 +198,8 @@ class EMSESPSettingsForm extends React.Component<EMSESPSettingsFormProps> {
|
|||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={4}>
|
<Grid item xs={4}>
|
||||||
<TextValidator
|
<TextValidator
|
||||||
validators={['required', 'isNumber', 'minNumber:0', 'maxNumber:40']}
|
validators={['required', 'isNumber', 'minNumber:0', 'maxNumber:40', 'matchRegexp:^((?!6|7|8|9|10|11|12|14|15|20|24|28|29|30|31)[0-9]*)$']}
|
||||||
errorMessages={['Button GPIO is required', "Must be a number", "Must be 0 or higher", "Max value is 40"]}
|
errorMessages={['GPIO is required', "Must be a number", "Must be 0 or higher", "Max value is 40", "Not a valid GPIO"]}
|
||||||
name="pbutton_gpio"
|
name="pbutton_gpio"
|
||||||
label="Button GPIO"
|
label="Button GPIO"
|
||||||
fullWidth
|
fullWidth
|
||||||
@@ -159,8 +212,8 @@ class EMSESPSettingsForm extends React.Component<EMSESPSettingsFormProps> {
|
|||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={4}>
|
<Grid item xs={4}>
|
||||||
<TextValidator
|
<TextValidator
|
||||||
validators={['required', 'isNumber', 'minNumber:0', 'maxNumber:40']}
|
validators={['required', 'isNumber', 'minNumber:0', 'maxNumber:40', 'matchRegexp:^((?!6|7|8|9|10|11|12|14|15|20|24|28|29|30|31)[0-9]*)$']}
|
||||||
errorMessages={['Dallas GPIO is required', "Must be a number", "Must be 0 or higher", "Max value is 40"]}
|
errorMessages={['GPIO is required', "Must be a number", "Must be 0 or higher", "Max value is 40", "Not a valid GPIO"]}
|
||||||
name="dallas_gpio"
|
name="dallas_gpio"
|
||||||
label="Dallas GPIO (0=none)"
|
label="Dallas GPIO (0=none)"
|
||||||
fullWidth
|
fullWidth
|
||||||
@@ -173,8 +226,8 @@ class EMSESPSettingsForm extends React.Component<EMSESPSettingsFormProps> {
|
|||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={4}>
|
<Grid item xs={4}>
|
||||||
<TextValidator
|
<TextValidator
|
||||||
validators={['required', 'isNumber', 'minNumber:0', 'maxNumber:40']}
|
validators={['required', 'isNumber', 'minNumber:0', 'maxNumber:40', 'matchRegexp:^((?!6|7|8|9|10|11|12|14|15|20|24|28|29|30|31)[0-9]*)$']}
|
||||||
errorMessages={['LED GPIO is required', "Must be a number", "Must be 0 or higher", "Max value is 40"]}
|
errorMessages={['GPIO is required', "Must be a number", "Must be 0 or higher", "Max value is 40", "Not a valid GPIO"]}
|
||||||
name="led_gpio"
|
name="led_gpio"
|
||||||
label="LED GPIO (0=none)"
|
label="LED GPIO (0=none)"
|
||||||
fullWidth
|
fullWidth
|
||||||
@@ -214,7 +267,7 @@ class EMSESPSettingsForm extends React.Component<EMSESPSettingsFormProps> {
|
|||||||
value="hide_led"
|
value="hide_led"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
label="Invert LED"
|
label = "Hide LED"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -361,4 +414,4 @@ class EMSESPSettingsForm extends React.Component<EMSESPSettingsFormProps> {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withWidth()(EMSESPSettingsForm);
|
export default withAuthenticatedContext(withWidth()(EMSESPSettingsForm));
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ export interface EMSESPSettings {
|
|||||||
analog_enabled: boolean;
|
analog_enabled: boolean;
|
||||||
pbutton_gpio: number;
|
pbutton_gpio: number;
|
||||||
trace_raw: boolean;
|
trace_raw: boolean;
|
||||||
board_profile: number;
|
board_profile: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum busConnectionStatus {
|
export enum busConnectionStatus {
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ class DummySettings {
|
|||||||
String staticIPConfig = "";
|
String staticIPConfig = "";
|
||||||
String dnsIP1 = "";
|
String dnsIP1 = "";
|
||||||
String dnsIP2 = "";
|
String dnsIP2 = "";
|
||||||
uint8_t board_profile = 0;
|
String board_profile = "CUSTOM";
|
||||||
uint16_t publish_time_boiler = 10;
|
uint16_t publish_time_boiler = 10;
|
||||||
uint16_t publish_time_thermostat = 10;
|
uint16_t publish_time_thermostat = 10;
|
||||||
uint16_t publish_time_solar = 10;
|
uint16_t publish_time_solar = 10;
|
||||||
|
|||||||
@@ -22,9 +22,16 @@ namespace emsesp {
|
|||||||
|
|
||||||
uint8_t WebSettings::flags_;
|
uint8_t WebSettings::flags_;
|
||||||
|
|
||||||
|
using namespace std::placeholders; // for `_1` etc
|
||||||
|
|
||||||
WebSettingsService::WebSettingsService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
|
WebSettingsService::WebSettingsService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
|
||||||
: _httpEndpoint(WebSettings::read, WebSettings::update, this, server, EMSESP_SETTINGS_SERVICE_PATH, securityManager)
|
: _httpEndpoint(WebSettings::read, WebSettings::update, this, server, EMSESP_SETTINGS_SERVICE_PATH, securityManager)
|
||||||
, _fsPersistence(WebSettings::read, WebSettings::update, this, fs, EMSESP_SETTINGS_FILE) {
|
, _fsPersistence(WebSettings::read, WebSettings::update, this, fs, EMSESP_SETTINGS_FILE)
|
||||||
|
, _boardProfileHandler(EMSESP_BOARD_PROFILE_SERVICE_PATH, securityManager->wrapCallback(std::bind(&WebSettingsService::board_profile, this, _1, _2), AuthenticationPredicates::IS_ADMIN)) {
|
||||||
|
_boardProfileHandler.setMethod(HTTP_POST);
|
||||||
|
_boardProfileHandler.setMaxContentLength(256);
|
||||||
|
server->addHandler(&_boardProfileHandler);
|
||||||
|
|
||||||
addUpdateHandler([&](const String & originId) { onUpdate(); }, false);
|
addUpdateHandler([&](const String & originId) { onUpdate(); }, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,4 +196,35 @@ void WebSettingsService::save() {
|
|||||||
_fsPersistence.writeToFS();
|
_fsPersistence.writeToFS();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// build the json profile to send back
|
||||||
|
void WebSettingsService::board_profile(AsyncWebServerRequest * request, JsonVariant & json) {
|
||||||
|
if (json.is<JsonObject>()) {
|
||||||
|
AsyncJsonResponse * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_MEDIUM);
|
||||||
|
JsonObject root = response->getRoot();
|
||||||
|
if (json.containsKey("code")) {
|
||||||
|
String board_profile = json["code"];
|
||||||
|
std::vector<uint8_t> data; // led, dallas, rx, tx, button
|
||||||
|
// check for valid board
|
||||||
|
if (System::load_board_profile(data, board_profile.c_str())) {
|
||||||
|
root["led_gpio"] = data[0];
|
||||||
|
root["dallas_gpio"] = data[1];
|
||||||
|
root["rx_gpio"] = data[2];
|
||||||
|
root["tx_gpio"] = data[3];
|
||||||
|
root["pbutton_gpio"] = data[4];
|
||||||
|
} else {
|
||||||
|
AsyncWebServerResponse * response = request->beginResponse(200);
|
||||||
|
request->send(response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
response->setLength();
|
||||||
|
request->send(response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AsyncWebServerResponse * response = request->beginResponse(200);
|
||||||
|
request->send(response);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace emsesp
|
} // namespace emsesp
|
||||||
@@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#define EMSESP_SETTINGS_FILE "/config/emsespSettings.json"
|
#define EMSESP_SETTINGS_FILE "/config/emsespSettings.json"
|
||||||
#define EMSESP_SETTINGS_SERVICE_PATH "/rest/emsespSettings"
|
#define EMSESP_SETTINGS_SERVICE_PATH "/rest/emsespSettings"
|
||||||
|
#define EMSESP_BOARD_PROFILE_SERVICE_PATH "/rest/boardProfile"
|
||||||
|
|
||||||
#define EMSESP_DEFAULT_TX_MODE 1 // EMS1.0
|
#define EMSESP_DEFAULT_TX_MODE 1 // EMS1.0
|
||||||
#define EMSESP_DEFAULT_TX_DELAY 0 // no delay
|
#define EMSESP_DEFAULT_TX_DELAY 0 // no delay
|
||||||
@@ -42,7 +43,7 @@
|
|||||||
#define EMSESP_DEFAULT_API_ENABLED false // turn off, because its insecure
|
#define EMSESP_DEFAULT_API_ENABLED false // turn off, because its insecure
|
||||||
#define EMSESP_DEFAULT_BOOL_FORMAT 1 // on/off
|
#define EMSESP_DEFAULT_BOOL_FORMAT 1 // on/off
|
||||||
#define EMSESP_DEFAULT_ANALOG_ENABLED false
|
#define EMSESP_DEFAULT_ANALOG_ENABLED false
|
||||||
#define EMSESP_DEFAULT_BOARD_PROFILE 0 // default ESP32
|
#define EMSESP_DEFAULT_BOARD_PROFILE "S32"
|
||||||
|
|
||||||
// Default GPIO PIN definitions
|
// Default GPIO PIN definitions
|
||||||
#if defined(ESP32)
|
#if defined(ESP32)
|
||||||
@@ -85,7 +86,7 @@ class WebSettings {
|
|||||||
bool api_enabled;
|
bool api_enabled;
|
||||||
bool analog_enabled;
|
bool analog_enabled;
|
||||||
uint8_t pbutton_gpio;
|
uint8_t pbutton_gpio;
|
||||||
uint8_t board_profile;
|
String board_profile;
|
||||||
|
|
||||||
static void read(WebSettings & settings, JsonObject & root);
|
static void read(WebSettings & settings, JsonObject & root);
|
||||||
static StateUpdateResult update(JsonObject & root, WebSettings & settings);
|
static StateUpdateResult update(JsonObject & root, WebSettings & settings);
|
||||||
@@ -137,8 +138,11 @@ class WebSettingsService : public StatefulService<WebSettings> {
|
|||||||
void save();
|
void save();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
HttpEndpoint<WebSettings> _httpEndpoint;
|
HttpEndpoint<WebSettings> _httpEndpoint;
|
||||||
FSPersistence<WebSettings> _fsPersistence;
|
FSPersistence<WebSettings> _fsPersistence;
|
||||||
|
AsyncCallbackJsonWebHandler _boardProfileHandler;
|
||||||
|
|
||||||
|
void board_profile(AsyncWebServerRequest * request, JsonVariant & json);
|
||||||
|
|
||||||
void onUpdate();
|
void onUpdate();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ MAKE_PSTR_WORD(master)
|
|||||||
MAKE_PSTR_WORD(pin)
|
MAKE_PSTR_WORD(pin)
|
||||||
MAKE_PSTR_WORD(publish)
|
MAKE_PSTR_WORD(publish)
|
||||||
MAKE_PSTR_WORD(timeout)
|
MAKE_PSTR_WORD(timeout)
|
||||||
MAKE_PSTR_WORD(ethernet)
|
MAKE_PSTR_WORD(board_profile)
|
||||||
|
|
||||||
// for commands
|
// for commands
|
||||||
MAKE_PSTR_WORD(call)
|
MAKE_PSTR_WORD(call)
|
||||||
@@ -101,6 +101,7 @@ MAKE_PSTR(master_thermostat_fmt, "Master Thermostat Device ID = %s")
|
|||||||
MAKE_PSTR(host_fmt, "Host = %s")
|
MAKE_PSTR(host_fmt, "Host = %s")
|
||||||
MAKE_PSTR(port_fmt, "Port = %d")
|
MAKE_PSTR(port_fmt, "Port = %d")
|
||||||
MAKE_PSTR(hostname_fmt, "Hostname = %s")
|
MAKE_PSTR(hostname_fmt, "Hostname = %s")
|
||||||
|
MAKE_PSTR(board_profile_fmt, "Board Profile = %s")
|
||||||
MAKE_PSTR(mark_interval_fmt, "Mark interval = %lus")
|
MAKE_PSTR(mark_interval_fmt, "Mark interval = %lus")
|
||||||
MAKE_PSTR(wifi_ssid_fmt, "WiFi SSID = %s")
|
MAKE_PSTR(wifi_ssid_fmt, "WiFi SSID = %s")
|
||||||
MAKE_PSTR(wifi_password_fmt, "WiFi Password = %S")
|
MAKE_PSTR(wifi_password_fmt, "WiFi Password = %S")
|
||||||
@@ -187,13 +188,6 @@ MAKE_PSTR_WORD(French)
|
|||||||
MAKE_PSTR_WORD(Italian)
|
MAKE_PSTR_WORD(Italian)
|
||||||
MAKE_PSTR_WORD(high)
|
MAKE_PSTR_WORD(high)
|
||||||
MAKE_PSTR_WORD(low)
|
MAKE_PSTR_WORD(low)
|
||||||
MAKE_PSTR(internal_temperature, "internal temperature")
|
|
||||||
MAKE_PSTR(internal_setpoint, "internal setpoint")
|
|
||||||
MAKE_PSTR(external_temperature, "external temperature")
|
|
||||||
MAKE_PSTR(burner_temperature, "burner temperature")
|
|
||||||
MAKE_PSTR(WW_temperature, "WW temperature")
|
|
||||||
MAKE_PSTR(functioning_mode, "functioning mode")
|
|
||||||
MAKE_PSTR(smoke_temperature, "smoke temperature")
|
|
||||||
MAKE_PSTR_WORD(radiator)
|
MAKE_PSTR_WORD(radiator)
|
||||||
MAKE_PSTR_WORD(convector)
|
MAKE_PSTR_WORD(convector)
|
||||||
MAKE_PSTR_WORD(floor)
|
MAKE_PSTR_WORD(floor)
|
||||||
@@ -212,6 +206,13 @@ MAKE_PSTR_WORD(night)
|
|||||||
MAKE_PSTR_WORD(day)
|
MAKE_PSTR_WORD(day)
|
||||||
MAKE_PSTR_WORD(holiday)
|
MAKE_PSTR_WORD(holiday)
|
||||||
MAKE_PSTR_WORD(reduce)
|
MAKE_PSTR_WORD(reduce)
|
||||||
|
MAKE_PSTR(internal_temperature, "internal temperature")
|
||||||
|
MAKE_PSTR(internal_setpoint, "internal setpoint")
|
||||||
|
MAKE_PSTR(external_temperature, "external temperature")
|
||||||
|
MAKE_PSTR(burner_temperature, "burner temperature")
|
||||||
|
MAKE_PSTR(WW_temperature, "WW temperature")
|
||||||
|
MAKE_PSTR(functioning_mode, "functioning mode")
|
||||||
|
MAKE_PSTR(smoke_temperature, "smoke temperature")
|
||||||
|
|
||||||
// thermostat lists
|
// thermostat lists
|
||||||
MAKE_PSTR_LIST(enum_ibaMainDisplay, F_(internal_temperature), F_(internal_setpoint), F_(external_temperature), F_(burner_temperature), F_(WW_temperature), F_(functioning_mode), F_(time), F_(date), F_(smoke_temperature))
|
MAKE_PSTR_LIST(enum_ibaMainDisplay, F_(internal_temperature), F_(internal_setpoint), F_(external_temperature), F_(burner_temperature), F_(WW_temperature), F_(functioning_mode), F_(time), F_(date), F_(smoke_temperature))
|
||||||
|
|||||||
@@ -203,12 +203,12 @@ void System::wifi_tweak() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check for valid ESP32 pins. This is very dependent on which ESP32 board is being used.
|
// check for valid ESP32 pins. This is very dependent on which ESP32 board is being used.
|
||||||
// Typically you can't use 1, 6-11 (SPI flash), 12, 14 & 15, 20, 24 and 28-31
|
// Typically you can't use 1, 6-11, 12, 14, 15, 20, 24, 28-31 and 40+
|
||||||
// we allow 0 as it has a special function on the NodeMCU apparently
|
// we allow 0 as it has a special function on the NodeMCU apparently
|
||||||
// See https://diyprojects.io/esp32-how-to-use-gpio-digital-io-arduino-code/#.YFpVEq9KhjG
|
// See https://diyprojects.io/esp32-how-to-use-gpio-digital-io-arduino-code/#.YFpVEq9KhjG
|
||||||
// and https://nodemcu.readthedocs.io/en/dev-esp32/modules/gpio/
|
// and https://nodemcu.readthedocs.io/en/dev-esp32/modules/gpio/
|
||||||
bool System::is_valid_gpio(uint8_t pin) {
|
bool System::is_valid_gpio(uint8_t pin) {
|
||||||
if ((pin == 1) || (pin >= 6 && pin <= 12) || (pin >= 14 && pin <= 15) || (pin == 20) || (pin == 24) || (pin >= 28 && pin <= 31)) {
|
if ((pin == 1) || (pin >= 6 && pin <= 12) || (pin >= 14 && pin <= 15) || (pin == 20) || (pin == 24) || (pin >= 28 && pin <= 31) || (pin > 40)) {
|
||||||
return false; // bad pin
|
return false; // bad pin
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -233,6 +233,8 @@ void System::start(uint32_t heap_start) {
|
|||||||
LOG_INFO(F("System %s booted (EMS-ESP version %s)"), networkSettings.hostname.c_str(), EMSESP_APP_VERSION); // print boot message
|
LOG_INFO(F("System %s booted (EMS-ESP version %s)"), networkSettings.hostname.c_str(), EMSESP_APP_VERSION); // print boot message
|
||||||
});
|
});
|
||||||
|
|
||||||
|
LOG_INFO("Loaded Board profile: %s", board_profile_.c_str());
|
||||||
|
|
||||||
commands_init(); // console & api commands
|
commands_init(); // console & api commands
|
||||||
led_init(false); // init LED
|
led_init(false); // init LED
|
||||||
adc_init(false); // analog ADC
|
adc_init(false); // analog ADC
|
||||||
@@ -321,7 +323,7 @@ void System::led_init(bool refresh) {
|
|||||||
|
|
||||||
if ((led_gpio_ != 0) && is_valid_gpio(led_gpio_)) {
|
if ((led_gpio_ != 0) && is_valid_gpio(led_gpio_)) {
|
||||||
pinMode(led_gpio_, OUTPUT); // 0 means disabled
|
pinMode(led_gpio_, OUTPUT); // 0 means disabled
|
||||||
digitalWrite(led_gpio_, hide_led_ ? !LED_ON : LED_ON); // LED on, forever
|
digitalWrite(led_gpio_, hide_led_ ? !LED_ON : LED_ON);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -470,6 +472,8 @@ void System::network_init(bool refresh) {
|
|||||||
last_system_check_ = 0; // force the LED to go from fast flash to pulse
|
last_system_check_ = 0; // force the LED to go from fast flash to pulse
|
||||||
send_heartbeat();
|
send_heartbeat();
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
// check board profile for those which use ethernet (id > 10)
|
// check board profile for those which use ethernet (id > 10)
|
||||||
// ethernet uses lots of additional memory so we only start it when it's explicitly set in the config
|
// ethernet uses lots of additional memory so we only start it when it's explicitly set in the config
|
||||||
if (board_profile_ < 10) {
|
if (board_profile_ < 10) {
|
||||||
@@ -531,6 +535,7 @@ void System::network_init(bool refresh) {
|
|||||||
"local");
|
"local");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
// check health of system, done every few seconds
|
// check health of system, done every few seconds
|
||||||
@@ -559,7 +564,7 @@ void System::system_check() {
|
|||||||
system_healthy_ = true;
|
system_healthy_ = true;
|
||||||
send_heartbeat();
|
send_heartbeat();
|
||||||
if (led_gpio_) {
|
if (led_gpio_) {
|
||||||
digitalWrite(led_gpio_, hide_led_ ? !LED_ON : LED_ON); // LED on, for ever
|
digitalWrite(led_gpio_, hide_led_ ? !LED_ON : LED_ON);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -568,7 +573,7 @@ void System::system_check() {
|
|||||||
|
|
||||||
// commands - takes static function pointers
|
// commands - takes static function pointers
|
||||||
// these commands respond to the topic "system" and take a payload like {cmd:"", data:"", id:""}
|
// these commands respond to the topic "system" and take a payload like {cmd:"", data:"", id:""}
|
||||||
// no individual subsribe for pin command because id is needed
|
// no individual subscribe for pin command because id is needed
|
||||||
void System::commands_init() {
|
void System::commands_init() {
|
||||||
Command::add(EMSdevice::DeviceType::SYSTEM, F_(pin), System::command_pin, MqttSubFlag::FLAG_NOSUB);
|
Command::add(EMSdevice::DeviceType::SYSTEM, F_(pin), System::command_pin, MqttSubFlag::FLAG_NOSUB);
|
||||||
Command::add(EMSdevice::DeviceType::SYSTEM, F_(send), System::command_send);
|
Command::add(EMSdevice::DeviceType::SYSTEM, F_(send), System::command_send);
|
||||||
@@ -779,7 +784,7 @@ void System::console_commands(Shell & shell, unsigned int context) {
|
|||||||
CommandFlags::ADMIN,
|
CommandFlags::ADMIN,
|
||||||
flash_string_vector{F_(set), F_(hostname)},
|
flash_string_vector{F_(set), F_(hostname)},
|
||||||
flash_string_vector{F_(name_mandatory)},
|
flash_string_vector{F_(name_mandatory)},
|
||||||
[](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments) {
|
[](Shell & shell, const std::vector<std::string> & arguments) {
|
||||||
shell.println("The network connection will be reset...");
|
shell.println("The network connection will be reset...");
|
||||||
Shell::loop_all();
|
Shell::loop_all();
|
||||||
delay(1000); // wait a second
|
delay(1000); // wait a second
|
||||||
@@ -823,39 +828,41 @@ void System::console_commands(Shell & shell, unsigned int context) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
EMSESPShell::commands->add_command(
|
EMSESPShell::commands->add_command(ShellContext::SYSTEM,
|
||||||
ShellContext::SYSTEM,
|
CommandFlags::ADMIN,
|
||||||
CommandFlags::ADMIN,
|
flash_string_vector{F_(set), F_(board_profile)},
|
||||||
flash_string_vector{F_(set), F_(ethernet)},
|
flash_string_vector{F_(name_mandatory)},
|
||||||
flash_string_vector{F_(n_mandatory)},
|
[](Shell & shell, const std::vector<std::string> & arguments) {
|
||||||
[](Shell & shell, const std::vector<std::string> & arguments) {
|
// check for valid profile
|
||||||
uint8_t n = Helpers::hextoint(arguments.front().c_str());
|
std::vector<uint8_t> data; // led, dallas, rx, tx, button
|
||||||
if (n <= 2) {
|
std::string board_profile = Helpers::toUpper(arguments.front());
|
||||||
EMSESP::webSettingsService.update(
|
if (!load_board_profile(data, board_profile)) {
|
||||||
[&](WebSettings & settings) {
|
shell.println(F("Invalid board profile"));
|
||||||
settings.board_profile = n;
|
return;
|
||||||
shell.printfln(F_(ethernet_option_fmt), n);
|
}
|
||||||
return StateUpdateResult::CHANGED;
|
shell.printfln("Loaded board profile %s with %d,%d,%d,%d,%d", board_profile.c_str(), data[0], data[1], data[2], data[3], data[4]);
|
||||||
},
|
EMSESP::webSettingsService.update(
|
||||||
"local");
|
[&](WebSettings & settings) {
|
||||||
EMSESP::system_.network_init(true);
|
settings.board_profile = board_profile.c_str();
|
||||||
} else {
|
settings.led_gpio = data[0];
|
||||||
shell.println(F("Must be 0, 1 or 2"));
|
settings.dallas_gpio = data[1];
|
||||||
}
|
settings.rx_gpio = data[2];
|
||||||
},
|
settings.tx_gpio = data[3];
|
||||||
[](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments __attribute__((unused))) -> const std::vector<std::string> {
|
settings.pbutton_gpio = data[4];
|
||||||
return std::vector<std::string>{read_flash_string(F("0")), read_flash_string(F("1")), read_flash_string(F("2"))};
|
return StateUpdateResult::CHANGED;
|
||||||
});
|
},
|
||||||
|
"local");
|
||||||
|
shell.printfln("Loaded board profile %s with %d,%d,%d,%d,%d", board_profile.c_str(), data[0], data[1], data[2], data[3], data[4]);
|
||||||
|
EMSESP::system_.network_init(true);
|
||||||
|
});
|
||||||
|
|
||||||
EMSESPShell::commands->add_command(ShellContext::SYSTEM, CommandFlags::USER, flash_string_vector{F_(set)}, [](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) {
|
EMSESPShell::commands->add_command(ShellContext::SYSTEM, CommandFlags::USER, flash_string_vector{F_(set)}, [](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) {
|
||||||
EMSESP::esp8266React.getNetworkSettingsService()->read([&](NetworkSettings & networkSettings) {
|
EMSESP::esp8266React.getNetworkSettingsService()->read([&](NetworkSettings & networkSettings) {
|
||||||
shell.print(F(" "));
|
|
||||||
shell.printfln(F_(hostname_fmt), networkSettings.hostname.isEmpty() ? uuid::read_flash_string(F_(unset)).c_str() : networkSettings.hostname.c_str());
|
shell.printfln(F_(hostname_fmt), networkSettings.hostname.isEmpty() ? uuid::read_flash_string(F_(unset)).c_str() : networkSettings.hostname.c_str());
|
||||||
shell.print(F(" "));
|
|
||||||
shell.printfln(F_(wifi_ssid_fmt), networkSettings.ssid.isEmpty() ? uuid::read_flash_string(F_(unset)).c_str() : networkSettings.ssid.c_str());
|
shell.printfln(F_(wifi_ssid_fmt), networkSettings.ssid.isEmpty() ? uuid::read_flash_string(F_(unset)).c_str() : networkSettings.ssid.c_str());
|
||||||
shell.print(F(" "));
|
|
||||||
shell.printfln(F_(wifi_password_fmt), networkSettings.ssid.isEmpty() ? F_(unset) : F_(asterisks));
|
shell.printfln(F_(wifi_password_fmt), networkSettings.ssid.isEmpty() ? F_(unset) : F_(asterisks));
|
||||||
});
|
});
|
||||||
|
EMSESP::webSettingsService.read([&](WebSettings & settings) { shell.printfln(F_(board_profile_fmt), settings.board_profile.c_str()); });
|
||||||
});
|
});
|
||||||
|
|
||||||
EMSESPShell::commands->add_command(ShellContext::SYSTEM, CommandFlags::ADMIN, flash_string_vector{F_(show), F_(users)}, [](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) {
|
EMSESPShell::commands->add_command(ShellContext::SYSTEM, CommandFlags::ADMIN, flash_string_vector{F_(show), F_(users)}, [](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) {
|
||||||
@@ -961,6 +968,7 @@ bool System::command_settings(const char * value, const int8_t id, JsonObject &
|
|||||||
node["api_enabled"] = settings.api_enabled;
|
node["api_enabled"] = settings.api_enabled;
|
||||||
node["analog_enabled"] = settings.analog_enabled;
|
node["analog_enabled"] = settings.analog_enabled;
|
||||||
node["pbutton_gpio"] = settings.pbutton_gpio;
|
node["pbutton_gpio"] = settings.pbutton_gpio;
|
||||||
|
node["board_profile"] = settings.board_profile;
|
||||||
});
|
});
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -1030,5 +1038,29 @@ bool System::command_test(const char * value, const int8_t id) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// takes a board profile and populates a data array with GPIO configurations
|
||||||
|
bool System::load_board_profile(std::vector<uint8_t> & data, const std::string & board_profile) {
|
||||||
|
if (board_profile == "S32") {
|
||||||
|
data = {2, 3, 23, 5, 0}; // Gateway S32
|
||||||
|
} else if (board_profile == "E32") {
|
||||||
|
data = {2, 4, 5, 17, 33}; // Gateway E32
|
||||||
|
} else if (board_profile == "MT-ET") {
|
||||||
|
data = {2, 4, 23, 5, 0}; // MT-ET Live D1 Mini
|
||||||
|
} else if (board_profile == "NODEMCU") {
|
||||||
|
data = {2, 4, 23, 5, 0}; // NodeMCU 32S
|
||||||
|
} else if (board_profile == "LOLIN") {
|
||||||
|
data = {2, 14, 17, 16, 0}; // Lolin D32
|
||||||
|
} else if (board_profile == "WEMOS") {
|
||||||
|
data = {2, 14, 17, 16, 0}; // Wemos Mini D1-32
|
||||||
|
} else if (board_profile == "OLIMEX") {
|
||||||
|
data = {32, 4, 5, 17, 34}; // Olimex ESP32-EVB-EA
|
||||||
|
} else if (board_profile == "TLK110") {
|
||||||
|
data = {2, 4, 5, 17, 33}; // Ethernet (TLK110)
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace emsesp
|
} // namespace emsesp
|
||||||
|
|||||||
@@ -76,6 +76,8 @@ class System {
|
|||||||
|
|
||||||
static bool is_valid_gpio(uint8_t pin);
|
static bool is_valid_gpio(uint8_t pin);
|
||||||
|
|
||||||
|
static bool load_board_profile(std::vector<uint8_t> & data, const std::string & board_profile);
|
||||||
|
|
||||||
bool check_upgrade();
|
bool check_upgrade();
|
||||||
void send_heartbeat();
|
void send_heartbeat();
|
||||||
|
|
||||||
@@ -115,7 +117,7 @@ class System {
|
|||||||
static constexpr uint32_t LED_WARNING_BLINK_FAST = 100; // flash quickly for boot up sequence
|
static constexpr uint32_t LED_WARNING_BLINK_FAST = 100; // flash quickly for boot up sequence
|
||||||
static constexpr uint32_t SYSTEM_HEARTBEAT_INTERVAL = 60000; // in milliseconds, how often the MQTT heartbeat is sent (1 min)
|
static constexpr uint32_t SYSTEM_HEARTBEAT_INTERVAL = 60000; // in milliseconds, how often the MQTT heartbeat is sent (1 min)
|
||||||
static constexpr uint32_t SYSTEM_MEASURE_ANALOG_INTERVAL = 500;
|
static constexpr uint32_t SYSTEM_MEASURE_ANALOG_INTERVAL = 500;
|
||||||
static constexpr uint8_t LED_ON = LOW; // internal LED
|
static constexpr uint8_t LED_ON = HIGH; // LED
|
||||||
|
|
||||||
#ifndef EMSESP_STANDALONE
|
#ifndef EMSESP_STANDALONE
|
||||||
static uuid::syslog::SyslogService syslog_;
|
static uuid::syslog::SyslogService syslog_;
|
||||||
@@ -145,7 +147,7 @@ class System {
|
|||||||
uint8_t led_gpio_;
|
uint8_t led_gpio_;
|
||||||
bool syslog_enabled_;
|
bool syslog_enabled_;
|
||||||
bool analog_enabled_;
|
bool analog_enabled_;
|
||||||
uint8_t board_profile_;
|
String board_profile_;
|
||||||
uint8_t pbutton_gpio_;
|
uint8_t pbutton_gpio_;
|
||||||
int8_t syslog_level_;
|
int8_t syslog_level_;
|
||||||
uint32_t syslog_mark_interval_;
|
uint32_t syslog_mark_interval_;
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
#define EMSESP_APP_VERSION "3.0.1b3"
|
#define EMSESP_APP_VERSION "3.0.1b4"
|
||||||
#define EMSESP_PLATFORM "ESP32"
|
#define EMSESP_PLATFORM "ESP32"
|
||||||
|
|||||||
Reference in New Issue
Block a user