URL updates

This commit is contained in:
proddy
2024-09-28 21:01:37 +02:00
parent f096c1b632
commit a2e41d6d1e
16 changed files with 277 additions and 177 deletions

View File

@@ -27,7 +27,7 @@
"@mui/icons-material": "^6.1.1",
"@mui/material": "^6.1.1",
"@table-library/react-table-library": "4.1.7",
"alova": "3.0.16",
"alova": "3.0.17",
"async-validator": "^4.2.5",
"jwt-decode": "^4.0.0",
"mime-types": "^2.1.35",
@@ -47,8 +47,8 @@
"@preact/preset-vite": "^2.9.1",
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
"@types/formidable": "^3",
"@types/node": "^22.7.3",
"@types/react": "^18.3.9",
"@types/node": "^22.7.4",
"@types/react": "^18.3.10",
"@types/react-dom": "^18.3.0",
"@types/react-router-dom": "^5.3.3",
"concurrently": "^9.0.1",
@@ -57,7 +57,7 @@
"formidable": "^3.5.1",
"prettier": "^3.3.3",
"rollup-plugin-visualizer": "^5.12.0",
"terser": "^5.34.0",
"terser": "^5.34.1",
"typescript-eslint": "8.7.0",
"vite": "^5.4.8",
"vite-plugin-imagemin": "^0.6.1",

View File

@@ -2,6 +2,7 @@ import { alovaInstance } from 'api/endpoints';
import type {
APIcall,
Action,
Activity,
CoreData,
DeviceData,
@@ -52,9 +53,9 @@ export const readActivity = () => alovaInstance.Get<Activity>('/rest/activity');
// API
export const API = (apiCall: APIcall) => alovaInstance.Post('/api', apiCall);
// DownloadUpload
export const exportData = (type: string) =>
alovaInstance.Get('/rest/exportData', { params: { type } });
// Generic action
export const callAction = (action: Action) =>
alovaInstance.Post('/rest/action', action);
// SettingsCustomization
export const readDeviceEntities = (id: number) =>
@@ -118,7 +119,7 @@ export const writeModules = (data: {
license: string;
}) => alovaInstance.Post('/rest/modules', data);
// SettingsEntities
// CustomEntities
export const readCustomEntities = () =>
alovaInstance.Get<EntityItem[]>('/rest/customEntities', {
transform(data) {

View File

@@ -1,4 +1,4 @@
import { useContext } from 'react';
import { useContext, useState } from 'react';
import { toast } from 'react-toastify';
import CommentIcon from '@mui/icons-material/CommentTwoTone';
@@ -16,18 +16,17 @@ import {
ListItemAvatar,
ListItemButton,
ListItemText,
Paper,
Stack,
Typography,
styled
Typography
} from '@mui/material';
import { useRequest } from 'alova/client';
import { SectionContent, useLayoutTitle } from 'components';
import { AuthenticatedContext } from 'contexts/authentication';
import { useI18nContext } from 'i18n/i18n-react';
import { saveFile } from 'utils/file';
import { API } from '../../api/app';
import { API, callAction } from '../../api/app';
import type { APIcall } from './types';
const Help = () => {
@@ -36,33 +35,79 @@ const Help = () => {
const { me } = useContext(AuthenticatedContext);
const { send: sendAPI } = useRequest((data: APIcall) => API(data), {
immediate: false
}).onSuccess((event) => {
const anchor = document.createElement('a');
anchor.href = URL.createObjectURL(
new Blob([JSON.stringify(event.data, null, 2)], {
type: 'text/plain'
})
);
const [customSupportIMG, setCustomSupportIMG] = useState<string | null>(null);
const [customSupportHTML, setCustomSupportHTML] = useState<string | null>(null);
anchor.download =
'emsesp_' + event.args[0].device + '_' + event.args[0].entity + '.txt';
anchor.click();
URL.revokeObjectURL(anchor.href);
toast.info(LL.DOWNLOAD_SUCCESSFUL());
});
useRequest(() => callAction({ action: 'customSupport' })).onSuccess(
(event: { data: { img_url: string; html: string[] } }) => {
if (event.data) {
setCustomSupportIMG(event.data.img_url);
setCustomSupportHTML(event.data.html.join('<br/>'));
}
}
);
const callAPI = async (device: string, cmd: string) => {
await sendAPI({ device, cmd, id: 0 }).catch((error: Error) => {
const { send: sendExportAllValues } = useRequest(
() => callAction({ action: 'export', param: 'allvalues' }),
{
immediate: false
}
)
.onSuccess((event) => {
saveFile(event.data, 'allvalues', '.txt');
toast.info(LL.DOWNLOAD_SUCCESSFUL());
})
.onError((error) => {
toast.error(error.message);
});
const { send: sendAPI } = useRequest((data: APIcall) => API(data), {
immediate: false
})
.onSuccess((event) => {
saveFile(event.data, 'system_info', '.json');
toast.info(LL.DOWNLOAD_SUCCESSFUL());
})
.onError((error) => {
toast.error(error.message);
});
};
return (
<>
<SectionContent>
{me.admin ? (
<Stack
padding={1}
mb={2}
direction="row"
divider={<Divider orientation="vertical" flexItem />}
sx={{
borderRadius: 3,
border: '2px solid grey',
justifyContent: 'space-evenly',
alignItems: 'center'
}}
>
<Typography variant="subtitle1">
{customSupportHTML ? (
<div dangerouslySetInnerHTML={{ __html: customSupportHTML }} />
) : (
LL.HELP_INFORMATION_5()
)}
</Typography>
<Box
component="img"
sx={{
maxHeight: 250
}}
src={
customSupportIMG
? customSupportIMG
: 'https://emsesp.org/_media/images/installer.jpeg'
}
/>
</Stack>
{me.admin && (
<List sx={{ borderRadius: 3, border: '2px solid grey' }}>
<ListItem>
<ListItemButton component="a" href="https://emsesp.org">
@@ -100,31 +145,6 @@ const Help = () => {
</ListItemButton>
</ListItem>
</List>
) : (
<Stack
spacing={1}
padding={1}
direction="row"
divider={<Divider orientation="vertical" flexItem />}
sx={{
borderRadius: 3,
border: '2px solid grey',
justifyContent: 'space-around',
alignItems: 'center'
}}
>
<Typography border="red" variant="subtitle1">
{LL.HELP_INFORMATION_5()}
</Typography>
<Box
padding={1}
component="img"
sx={{
maxHeight: { xs: 100, md: 250 }
}}
src="https://emsesp.org/_media/images/installer.jpeg"
/>
</Stack>
)}
<Box p={2} color="warning.main">
@@ -135,7 +155,7 @@ const Help = () => {
startIcon={<DownloadIcon />}
variant="outlined"
color="primary"
onClick={() => callAPI('system', 'info')}
onClick={() => sendAPI({ device: 'system', cmd: 'info', id: 0 })}
>
{LL.DOWNLOAD(1)}&nbsp;{LL.SUPPORT_INFORMATION(0)}
</Button>
@@ -146,7 +166,7 @@ const Help = () => {
startIcon={<DownloadIcon />}
variant="outlined"
color="primary"
onClick={() => callAPI('system', 'allvalues')}
onClick={() => sendExportAllValues()}
>
{LL.DOWNLOAD(1)}&nbsp;{LL.ALLVALUES()}
</Button>

View File

@@ -265,6 +265,12 @@ export interface APIcall {
cmd: string;
id: number;
}
export interface Action {
action: string;
param?: string; // optional
}
export interface WriteAnalogSensor {
id: number;
gpio: number;

View File

@@ -18,7 +18,7 @@ import {
import Grid from '@mui/material/Grid2';
import * as SystemApi from 'api/system';
import { API, exportData } from 'api/app';
import { API, callAction } from 'api/app';
import {
checkUpgrade,
getDevVersion,
@@ -37,6 +37,7 @@ import {
useLayoutTitle
} from 'components';
import { useI18nContext } from 'i18n/i18n-react';
import { saveFile } from 'utils/file';
const DownloadUpload = () => {
const { LL } = useI18nContext();
@@ -46,11 +47,23 @@ const DownloadUpload = () => {
const [useDev, setUseDev] = useState<boolean>(false);
const [upgradeAvailable, setUpgradeAvailable] = useState<boolean>(false);
const { send: sendExportData } = useRequest((type: string) => exportData(type), {
immediate: false
})
const { send: sendCheckUpgrade } = useRequest(
(version: string) => callAction({ action: 'checkUpgrade', param: version }),
{
immediate: false
}
).onSuccess((event) => {
setUpgradeAvailable((event.data as { upgradeable: boolean }).upgradeable);
});
const { send: sendExportData } = useRequest(
(type: string) => callAction({ action: 'export', param: type }),
{
immediate: false
}
)
.onSuccess((event) => {
saveFile(event.data, event.args[0]);
saveFile(event.data, event.args[0], '.json');
toast.info(LL.DOWNLOAD_SUCCESSFUL());
})
.onError((error) => {
@@ -83,12 +96,6 @@ const DownloadUpload = () => {
);
};
const { send: sendCheckUpgrade } = useRequest(checkUpgrade, {
immediate: false
}).onSuccess((event) => {
setUpgradeAvailable(event.data.upgradeable);
});
// called immediately to get the latest version, on page load
const { data: latestVersion } = useRequest(getStableVersion, {
// uncomment next 2 lines for testing, uses https://github.com/emsesp/EMS-ESP32/releases/download/v3.6.5/EMS-ESP-3_6_5-ESP32-16MB+.bin
@@ -102,7 +109,7 @@ const DownloadUpload = () => {
// immediate: false,
// initialData: '3.7.0-dev.32'
}).onSuccess((event) => {
void sendCheckUpgrade({ version: event.data });
void sendCheckUpgrade(event.data);
});
const STABLE_URL = 'https://github.com/emsesp/EMS-ESP32/releases/download/';
@@ -142,18 +149,6 @@ const DownloadUpload = () => {
setRestarting(true);
};
const saveFile = (json: unknown, filename: string) => {
const anchor = document.createElement('a');
anchor.href = URL.createObjectURL(
new Blob([JSON.stringify(json, null, 2)], {
type: 'text/plain'
})
);
anchor.download = 'emsesp_' + filename + '.json';
anchor.click();
URL.revokeObjectURL(anchor.href);
};
useLayoutTitle(LL.DOWNLOAD_UPLOAD());
const internet_live =

View File

@@ -0,0 +1,11 @@
export const saveFile = (json: unknown, filename: string, extension: string) => {
const anchor = document.createElement('a');
anchor.href = URL.createObjectURL(
new Blob([JSON.stringify(json, null, 2)], {
type: 'text/plain'
})
);
anchor.download = 'emsesp_' + filename + extension;
anchor.click();
URL.revokeObjectURL(anchor.href);
};

View File

@@ -1446,12 +1446,12 @@ __metadata:
languageName: node
linkType: hard
"@types/node@npm:^22.7.3":
version: 22.7.3
resolution: "@types/node@npm:22.7.3"
"@types/node@npm:^22.7.4":
version: 22.7.4
resolution: "@types/node@npm:22.7.4"
dependencies:
undici-types: "npm:~6.19.2"
checksum: 10c0/0e579813528b0370454337a952f43b792cd12731e10fdca0fdb627158e980c1219bba99e9048c134b6a19325d817016059afe016ccd372326c838a1b85a51574
checksum: 10c0/c22bf54515c78ff3170142c1e718b90e2a0003419dc2d55f79c9c9362edd590a6ab1450deb09ff6e1b32d1b4698da407930b16285e8be3a009ea6cd2695cac01
languageName: node
linkType: hard
@@ -1518,13 +1518,13 @@ __metadata:
languageName: node
linkType: hard
"@types/react@npm:^18.3.9":
version: 18.3.9
resolution: "@types/react@npm:18.3.9"
"@types/react@npm:^18.3.10":
version: 18.3.10
resolution: "@types/react@npm:18.3.10"
dependencies:
"@types/prop-types": "npm:*"
csstype: "npm:^3.0.2"
checksum: 10c0/a92b8e061d0c833e096254782c56a802316593f4a907fb834b557cabe848a0829b9eb6056404ea239eb4d5ec5ac7b7724309761516c0a7a277916fa04dd4f805
checksum: 10c0/f5be1de1b0331c1fdb33d577f4cf7f1b949d4bded5347b2351a537f03c51dade5be115e21b161dcf1b37061954d320f6a0bdf8d7b70e24eda51071fdd614383d
languageName: node
linkType: hard
@@ -1678,11 +1678,11 @@ __metadata:
"@table-library/react-table-library": "npm:4.1.7"
"@trivago/prettier-plugin-sort-imports": "npm:^4.3.0"
"@types/formidable": "npm:^3"
"@types/node": "npm:^22.7.3"
"@types/react": "npm:^18.3.9"
"@types/node": "npm:^22.7.4"
"@types/react": "npm:^18.3.10"
"@types/react-dom": "npm:^18.3.0"
"@types/react-router-dom": "npm:^5.3.3"
alova: "npm:3.0.16"
alova: "npm:3.0.17"
async-validator: "npm:^4.2.5"
concurrently: "npm:^9.0.1"
eslint: "npm:^9.11.1"
@@ -1698,7 +1698,7 @@ __metadata:
react-router-dom: "npm:^6.26.2"
react-toastify: "npm:^10.0.5"
rollup-plugin-visualizer: "npm:^5.12.0"
terser: "npm:^5.34.0"
terser: "npm:^5.34.1"
typesafe-i18n: "npm:^5.26.2"
typescript: "npm:^5.6.2"
typescript-eslint: "npm:8.7.0"
@@ -1764,13 +1764,13 @@ __metadata:
languageName: node
linkType: hard
"alova@npm:3.0.16":
version: 3.0.16
resolution: "alova@npm:3.0.16"
"alova@npm:3.0.17":
version: 3.0.17
resolution: "alova@npm:3.0.17"
dependencies:
"@alova/shared": "npm:^1.0.5"
rate-limiter-flexible: "npm:^5.0.3"
checksum: 10c0/66cb597f4f00feda04b7619dd852fde92bc920cc97b018be70791240c8e8c64677a998a02a684f3aace5997322236a677264f25afe6bcaf4ec856ae42be859a8
checksum: 10c0/e8a2ae885a3ff44dafec230d9388dc22b6445bb0cf8511fc9855b5a98ad9961941b0d33a7da874df23db4af0dba75872a470e3edebbdcc5ead8aecbc7fcc3d6b
languageName: node
linkType: hard
@@ -6654,9 +6654,9 @@ __metadata:
languageName: node
linkType: hard
"terser@npm:^5.34.0":
version: 5.34.0
resolution: "terser@npm:5.34.0"
"terser@npm:^5.34.1":
version: 5.34.1
resolution: "terser@npm:5.34.1"
dependencies:
"@jridgewell/source-map": "npm:^0.3.3"
acorn: "npm:^8.8.2"
@@ -6664,7 +6664,7 @@ __metadata:
source-map-support: "npm:~0.5.20"
bin:
terser: bin/terser
checksum: 10c0/74e8ef4e565e5600415cd9377a90eed419b8076465d453c0c76aef4053c45371512d2de76c34d01e004cdd49ea5a749d77eeb343f7e665b2d172158ca08ba23e
checksum: 10c0/51c7d704c5c4ae88bf937124112c9972aed4e1fd29d805cc2d86e0f54cd631ecd4e69db5bb3c1e3b450c741c86e2313328bea0fde925329e8a31a07a7941723c
languageName: node
linkType: hard

View File

@@ -117,6 +117,55 @@ function updateMask(entity: any, de: any, dd: any) {
}
}
// called by Action endpoint
function export_data(type: string) {
console.log('exporting ' + type + '...');
switch (type) {
case 'settings':
return emsesp_info;
case 'customizations':
return emsesp_deviceentities_2; // fixed for one device
case 'entities':
return emsesp_customentities;
case 'schedule':
return emsesp_schedule;
case 'modules':
return emsesp_modules;
case 'allvalues':
return emsesp_allvalues;
default:
return status(404);
}
}
// called by Action endpoint
function custom_support() {
return {
html: [
'This product is installed and managed by:',
'',
'<b>Bosch Installer Example</b>',
'Nefit Road 12',
'1234 AB Amsterdam',
'Phone: +31 123 456 789',
'email: support@boschinstaller.nl',
'',
"For help and questions please <a target='_blank' href='https://emsesp.org'>contact</a> your installer."
],
img_url: 'https://emsesp.org/_media/images/designer.png'
};
}
// called by Action endpoint
function check_upgrade(version: string) {
console.log('check upgrade from version', version);
const data = {
upgradeable: true
// upgradeable: false
};
return data;
}
// START DATA
// LOG
@@ -402,7 +451,6 @@ const EMSESP_DEVICEDATA_ENDPOINT2 = REST_ENDPOINT_ROOT + 'deviceData/:id?';
const EMSESP_DEVICEENTITIES_ENDPOINT1 = REST_ENDPOINT_ROOT + 'deviceEntities';
const EMSESP_DEVICEENTITIES_ENDPOINT2 = REST_ENDPOINT_ROOT + 'deviceEntities/:id?';
const EMSESP_CHECK_UPGRADE_ENDPOINT = REST_ENDPOINT_ROOT + 'checkUpgrade';
const EMSESP_BOARDPROFILE_ENDPOINT = REST_ENDPOINT_ROOT + 'boardProfile';
const EMSESP_WRITE_DEVICEVALUE_ENDPOINT = REST_ENDPOINT_ROOT + 'writeDeviceValue';
const EMSESP_WRITE_DEVICENAME_ENDPOINT = REST_ENDPOINT_ROOT + 'writeDeviceName';
@@ -416,7 +464,8 @@ const EMSESP_RESET_CUSTOMIZATIONS_ENDPOINT =
const EMSESP_SCHEDULE_ENDPOINT = REST_ENDPOINT_ROOT + 'schedule';
const EMSESP_CUSTOMENTITIES_ENDPOINT = REST_ENDPOINT_ROOT + 'customEntities';
const EMSESP_MODULES_ENDPOINT = REST_ENDPOINT_ROOT + 'modules';
const EMSESP_EXPORT_DATA_ENDPOINT = REST_ENDPOINT_ROOT + 'exportData';
const EMSESP_ACTION_ENDPOINT = REST_ENDPOINT_ROOT + 'action';
// these are used in the API calls only
const EMSESP_SYSTEM_INFO_ENDPOINT = API_ENDPOINT_ROOT + 'system/info';
@@ -4081,16 +4130,10 @@ router
router
.get(ACTIVITY_ENDPOINT, () => activity)
.get(SYSTEM_STATUS_ENDPOINT, () => {
if (countHardwarePoll === 0) {
console.log('Resetting hardware count...');
}
if (countHardwarePoll >= 2) {
countHardwarePoll = 0;
system_status.status = 'ready';
}
console.log('Hardware count ' + countHardwarePoll + ' of 2');
countHardwarePoll++;
return system_status;
@@ -4402,17 +4445,6 @@ router
return status(200);
})
// check upgrade
.post(EMSESP_CHECK_UPGRADE_ENDPOINT, async (request: any) => {
const content = await request.json();
console.log('check upgrade from ', content.version);
const data = {
upgradeable: true
// upgradeable: false
};
return data;
})
// Settings - board profile
.get(EMSESP_BOARDPROFILE_ENDPOINT, (request) => {
const board_profile = request.query.boardProfile;
@@ -4549,32 +4581,32 @@ router
return data;
})
// Download Settings
.get(EMSESP_EXPORT_DATA_ENDPOINT, (request) => {
const type = request.query.type;
console.log('exporting ' + type + ' data');
switch (type) {
case 'settings':
return emsesp_info;
case 'customizations':
return emsesp_deviceentities_2; // fixed for one device
case 'entities':
return emsesp_customentities;
case 'schedule':
return emsesp_schedule;
case 'modules':
return emsesp_modules;
default:
return status(404);
}
})
// upload URL
.post('/rest/uploadURL', () => {
console.log('upload File from URL');
return status(200);
})
// generic action for all /rest/... endpoints
// takes an action and param in JSON
.post(EMSESP_ACTION_ENDPOINT, async (request: any) => {
const content = await request.json();
if (content.hasOwnProperty('action')) {
const action = content.action;
if (action === 'export') {
// export data
return export_data(content.param);
} else if (action === 'customSupport') {
// send custom support
return custom_support();
} else if (action === 'checkUpgrade') {
// check upgrade
return check_upgrade(content.param);
}
}
return status(404); // cmd not found
})
// API which are usually POST for security
.post(EMSESP_SYSTEM_INFO_ENDPOINT, () => emsesp_info)
.get(EMSESP_SYSTEM_INFO_ENDPOINT, () => emsesp_info)
@@ -4594,9 +4626,6 @@ router
if (cmd === 'info') {
return emsesp_info;
}
if (cmd === 'allvalues') {
return emsesp_allvalues;
}
if (cmd === 'format') {
console.log('formatting...');
return status(200);

View File

@@ -39,7 +39,7 @@ unbuild_flags =
${common.core_unbuild_flags}
[espressif32_base]
platform = espressif32@6.8.1
platform = espressif32@6.9.0
framework = arduino
board_build.filesystem = littlefs
build_flags =

View File

@@ -75,7 +75,7 @@ MAKE_WORD_TRANSLATION(schedule_cmd, "enable schedule item", "Aktiviere Zeitplane
MAKE_WORD_TRANSLATION(entity_cmd, "set custom value on ems", "Sende eigene Entitäten zu EMS", "verstuur custom waarde naar EMS", "", "wyślij własną wartość na EMS", "", "", "emp üzerinde özel değer ayarla", "imposta valori personalizzati su EMS", "nastaviť vlastnú hodnotu na ems") // TODO translate
MAKE_WORD_TRANSLATION(commands_response, "get response", "Hole Antwort", "Verzoek om antwoord", "", "uzyskaj odpowiedź", "", "", "gelen cevap", "", "získať odpoveď") // TODO translate
MAKE_WORD_TRANSLATION(coldshot_cmd, "send a cold shot of water", "Zugabe einer Menge kalten Wassers", "", "", "uruchom tryśnięcie zimnej wody", "", "", "soğuk su gönder", "", "pošlite studenú dávku vody") // TODO translate
MAKE_WORD_TRANSLATION(allvalues_cmd, "output all values in system", "Alle Werte im System ausgeben", "", "", "wyświetl wszystkie wartości", "", "", "", "", "vypísať všetky hodnoty") // TODO translate
MAKE_WORD_TRANSLATION(allvalues_cmd, "output all values in system", "Alle Werte im System ausgeben", "", "", "wyświetl wszystkie wartości", "", "", "", "", "vypísať všetky hodnoty") // TODO remove
MAKE_WORD_TRANSLATION(message_cmd, "send a message", "Eine Nachricht senden", "", "", "", "", "", "", "", "poslať správu") // TODO translate
MAKE_WORD_TRANSLATION(values_cmd, "list all values", "Liste alle Werte auf", "", "", "", "", "", "", "", "vypísať všetky hodnoty") // TODO translate

View File

@@ -113,6 +113,7 @@ bool System::command_response(const char * value, const int8_t id, JsonObject ou
// output all the devices and the values
// not system info
// TODO remove?
bool System::command_allvalues(const char * value, const int8_t id, JsonObject output) {
JsonDocument doc;
JsonObject device_output;
@@ -874,7 +875,7 @@ void System::commands_init() {
// these commands will return data in JSON format
Command::add(EMSdevice::DeviceType::SYSTEM, F("response"), System::command_response, FL_(commands_response));
Command::add(EMSdevice::DeviceType::SYSTEM, F("allvalues"), System::command_allvalues, FL_(allvalues_cmd));
Command::add(EMSdevice::DeviceType::SYSTEM, F("allvalues"), System::command_allvalues, FL_(allvalues_cmd)); // TODO remove
// MQTT subscribe "ems-esp/system/#"
Mqtt::subscribe(EMSdevice::DeviceType::SYSTEM, "system/#", nullptr); // use empty function callback
@@ -1139,7 +1140,7 @@ void System::show_system(uuid::console::Shell & shell) {
// see if there is a restore of an older settings file that needs to be applied
bool System::check_restore() {
bool reboot_required = false;
bool reboot_required = false; // true if we need to reboot
#ifndef EMSESP_STANDALONE
File new_file = LittleFS.open(TEMP_FILENAME_PATH);
@@ -1167,11 +1168,20 @@ bool System::check_restore() {
} else if (settings_type == "entities") {
// it's a entity file, just replace it and there's no need to reboot
saveSettings(EMSESP_CUSTOMENTITY_FILE, "Entities", input);
} else if (settings_type == "custom_support") {
// it's a custom support file - save it to /config
new_file.close();
if (LittleFS.rename(TEMP_FILENAME_PATH, EMSESP_CUSTOMSUPPORT_FILE)) {
LOG_INFO("Custom support information loaded");
return false; // no need to reboot
} else {
LOG_ERROR("Failed to save custom support file");
}
} else {
LOG_ERROR("Unrecognized file uploaded");
}
} else {
LOG_ERROR("Unrecognized file uploaded, not json. Will be removed.");
LOG_ERROR("Unrecognized file uploaded, not json.");
}
// close (just in case) and remove the temp file

View File

@@ -43,6 +43,8 @@ using uuid::console::Shell;
#define EMSESP_FS_CONFIG_DIRECTORY "/config"
#define EMSESP_CUSTOMSUPPORT_FILE "/config/customSupport.json"
namespace emsesp {
enum PHY_type : uint8_t { PHY_TYPE_NONE = 0, PHY_TYPE_LAN8720, PHY_TYPE_TLK110 };
@@ -63,7 +65,7 @@ class System {
static bool command_message(const char * value, const int8_t id);
static bool command_info(const char * value, const int8_t id, JsonObject output);
static bool command_response(const char * value, const int8_t id, JsonObject output);
static bool command_allvalues(const char * value, const int8_t id, JsonObject output);
static bool command_allvalues(const char * value, const int8_t id, JsonObject output); // TODO fix
static bool get_value_info(JsonObject root, const char * cmd);
static void get_value_json(JsonObject output, const std::string & circuit, const std::string & name, JsonVariant val);

View File

@@ -327,7 +327,6 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
// shell.invoke_command("show devices");
// shell.invoke_command("show values");
// shell.invoke_command("call system allvalues");
// shell.invoke_command("call system publish");
// shell.invoke_command("show mqtt");
ok = true;
@@ -792,7 +791,6 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
shell.invoke_command("call temperaturesensor");
shell.invoke_command("show values");
shell.invoke_command("call system allvalues");
shell.invoke_command("call temperaturesensor info");
shell.invoke_command("call temperaturesensor values");
@@ -842,7 +840,6 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
shell.invoke_command("call analogsensor");
shell.invoke_command("show values");
shell.invoke_command("call system allvalues");
shell.invoke_command("call analogsensor info");
shell.invoke_command("call analogsensor values");

View File

@@ -463,7 +463,6 @@ uint8_t WebCustomEntityService::count_entities() {
uint8_t count = 0;
for (const CustomEntityItem & entity : *customEntityItems_) {
render_value(output, entity);
// TODO check JsonVariant
if (output[entity.name].is<JsonVariantConst>() || entity.writeable) {
count++;
}

View File

@@ -27,10 +27,9 @@ namespace emsesp {
WebStatusService::WebStatusService(AsyncWebServer * server, SecurityManager * securityManager) {
// GET
server->on(EMSESP_SYSTEM_STATUS_SERVICE_PATH, HTTP_GET, [this](AsyncWebServerRequest * request) { systemStatus(request); });
server->on(EMSESP_EXPORT_DATA_SERVICE_PATH, HTTP_GET, [this](AsyncWebServerRequest * request) { exportData(request); });
// POST
server->on(EMSESP_CHECK_UPGRADE_PATH, [this](AsyncWebServerRequest * request, JsonVariant json) { checkUpgrade(request, json); });
// generic action - POST
server->on(EMSESP_ACTION_SERVICE_PATH, [this](AsyncWebServerRequest * request, JsonVariant json) { action(request, json); });
}
// /rest/systemStatus
@@ -146,13 +145,42 @@ void WebStatusService::systemStatus(AsyncWebServerRequest * request) {
request->send(response);
}
// returns trues if there is an upgrade available
void WebStatusService::checkUpgrade(AsyncWebServerRequest * request, JsonVariant json) {
// generic action handler - as a POST
void WebStatusService::action(AsyncWebServerRequest * request, JsonVariant json) {
auto * response = new AsyncJsonResponse();
JsonObject root = response->getRoot();
// get action and optional param
std::string action = json["action"];
std::string param = json["param"]; // is optional
// TODO remove
Serial.printf("Action: %s\n", action.c_str());
Serial.printf("Param: %s\n", param.c_str());
bool ok = true;
if (action == "checkUpgrade") {
ok = checkUpgrade(root, param);
} else if (action == "export") {
ok = exportData(root, param);
} else if (action == "customSupport") {
ok = customSupport(root);
}
// send response
if (!ok) {
request->send(400);
return;
}
response->setLength();
request->send(response);
}
// returns true if there is an upgrade available
bool WebStatusService::checkUpgrade(JsonObject root, std::string & latest_version) {
version::Semver200_version settings_version(EMSESP_APP_VERSION);
const std::string latest_version = json["version"] | EMSESP_APP_VERSION;
version::Semver200_version this_version(latest_version);
#if defined(EMSESP_DEBUG)
@@ -161,16 +189,11 @@ void WebStatusService::checkUpgrade(AsyncWebServerRequest * request, JsonVariant
root["upgradeable"] = (this_version > settings_version);
response->setLength();
request->send(response);
return true;
}
// returns data for a specific feature/settings as a json object
void WebStatusService::exportData(AsyncWebServerRequest * request) {
auto * response = new AsyncJsonResponse();
JsonObject root = response->getRoot();
String type = request->getParam("type")->value();
bool WebStatusService::exportData(JsonObject root, std::string & type) {
root["type"] = type;
if (type == "settings") {
@@ -189,12 +212,15 @@ void WebStatusService::exportData(AsyncWebServerRequest * request) {
} else if (type == "entities") {
System::extractSettings(EMSESP_CUSTOMENTITY_FILE, "Entities", root);
} else {
request->send(400);
return;
return false;
}
return true;
}
response->setLength();
request->send(response);
// custom support
bool WebStatusService::customSupport(JsonObject root) {
root["custom_support"] = true;
return true;
}
} // namespace emsesp

View File

@@ -2,8 +2,8 @@
#define WebStatusService_h
#define EMSESP_SYSTEM_STATUS_SERVICE_PATH "/rest/systemStatus"
#define EMSESP_CHECK_UPGRADE_PATH "/rest/checkUpgrade"
#define EMSESP_EXPORT_DATA_SERVICE_PATH "/rest/exportData"
#define EMSESP_ACTION_SERVICE_PATH "/rest/action"
#include <semver200.h> // for version checking
@@ -13,10 +13,14 @@ class WebStatusService {
public:
WebStatusService(AsyncWebServer * server, SecurityManager * securityManager);
private:
protected:
void systemStatus(AsyncWebServerRequest * request);
void checkUpgrade(AsyncWebServerRequest * request, JsonVariant json);
void exportData(AsyncWebServerRequest * request);
void action(AsyncWebServerRequest * request, JsonVariant json);
private:
bool checkUpgrade(JsonObject root, std::string & latest_version);
bool exportData(JsonObject root, std::string & type);
bool customSupport(JsonObject root);
};
} // namespace emsesp