This commit is contained in:
MichaelDvP
2024-07-26 18:30:14 +02:00
13 changed files with 87 additions and 72 deletions

View File

@@ -7,9 +7,9 @@ import type { HardwareStatus, LogSettings, SystemStatus } from 'types';
import { alovaInstance, alovaInstanceGH } from './endpoints'; import { alovaInstance, alovaInstanceGH } from './endpoints';
// HardwareStatus - also used to ping in Restart monitor for pinging // hardwareStatus - also used to ping in Restart monitor for pinging
export const readHardwareStatus = () => export const readHardwareStatus = () =>
alovaInstance.Get<HardwareStatus>('/rest/HardwareStatus'); alovaInstance.Get<HardwareStatus>('/rest/hardwareStatus');
// SystemStatus // SystemStatus
export const readSystemStatus = () => export const readSystemStatus = () =>

View File

@@ -50,6 +50,10 @@ export function boardProfileSelectItems() {
} }
const ApplicationSettings: FC = () => { const ApplicationSettings: FC = () => {
const { data: hardwareData, error } = useRequest(SystemApi.readHardwareStatus, {
force: true
});
const { const {
loadData, loadData,
saveData, saveData,
@@ -835,7 +839,7 @@ const ApplicationSettings: FC = () => {
checked={data.modbus_enabled} checked={data.modbus_enabled}
onChange={updateFormValue} onChange={updateFormValue}
name="modbus_enabled" name="modbus_enabled"
disabled={saving} disabled={!hardwareData.psram}
/> />
} }
label={LL.ENABLE_MODBUS()} label={LL.ENABLE_MODBUS()}

View File

@@ -21,6 +21,7 @@ export interface HardwareStatus {
fs_used: number; fs_used: number;
fs_free: number; fs_free: number;
free_mem: number; free_mem: number;
psram: boolean;
psram_size?: number; psram_size?: number;
free_psram?: number; free_psram?: number;
has_loader: boolean; has_loader: boolean;

View File

@@ -336,7 +336,7 @@ const SYSTEM_STATUS_ENDPOINT = REST_ENDPOINT_ROOT + 'systemStatus';
const ACTIVITY_ENDPOINT = REST_ENDPOINT_ROOT + 'activity'; const ACTIVITY_ENDPOINT = REST_ENDPOINT_ROOT + 'activity';
// SETTINGS // SETTINGS
const HARDWARE_STATUS_ENDPOINT = REST_ENDPOINT_ROOT + 'HardwareStatus'; const HARDWARE_STATUS_ENDPOINT = REST_ENDPOINT_ROOT + 'hardwareStatus';
const SECURITY_SETTINGS_ENDPOINT = REST_ENDPOINT_ROOT + 'securitySettings'; const SECURITY_SETTINGS_ENDPOINT = REST_ENDPOINT_ROOT + 'securitySettings';
const RESTART_ENDPOINT = REST_ENDPOINT_ROOT + 'restart'; const RESTART_ENDPOINT = REST_ENDPOINT_ROOT + 'restart';
const RESTART_PARTITION_ENDPOINT = REST_ENDPOINT_ROOT + 'partition'; const RESTART_PARTITION_ENDPOINT = REST_ENDPOINT_ROOT + 'partition';
@@ -366,6 +366,8 @@ const hardware_status = {
fs_used: 24, fs_used: 24,
fs_free: 2024, fs_free: 2024,
free_mem: 100, free_mem: 100,
psram: true,
// psram: false,
psram_size: 4093, psram_size: 4093,
free_psram: 4074, free_psram: 4074,
has_loader: true, has_loader: true,
@@ -604,42 +606,53 @@ const emsesp_allvalues = {
}; };
let settings = { let settings = {
locale: 'en', "locale": "en",
tx_mode: 4, "tx_mode": 1,
ems_bus_id: 11, "ems_bus_id": 11,
syslog_enabled: false, "syslog_enabled": false,
syslog_level: 3, "syslog_level": 3,
trace_raw: false, "trace_raw": false,
syslog_mark_interval: 0, "syslog_mark_interval": 0,
syslog_host: '192.168.1.4', "syslog_host": "192.168.1.8",
syslog_port: 514, "syslog_port": 514,
shower_timer: true, "boiler_heatingoff": false,
shower_alert: true, "remote_timeout": 24,
shower_alert_trigger: 7, "remote_timeout_en": false,
shower_alert_coldshot: 10, "shower_timer": true,
shower_min_duration: 120, "shower_alert": false,
rx_gpio: 23, "shower_alert_coldshot": 10,
tx_gpio: 5, "shower_alert_trigger": 7,
phy_type: 0, "shower_min_duration": 180,
eth_power: 0, "rx_gpio": 4,
eth_phy_addr: 0, "tx_gpio": 5,
eth_clock_mode: 0, "dallas_gpio": 14,
dallas_gpio: 3, "dallas_parasite": false,
dallas_parasite: false, "led_gpio": 2,
led_gpio: 2, "hide_led": true,
hide_led: false, "low_clock": false,
notoken_api: false, "telnet_enabled": true,
readonly_mode: false, "notoken_api": false,
low_clock: false, "readonly_mode": false,
boiler_heatingoff: false, "analog_enabled": true,
telnet_enabled: true, "pbutton_gpio": 34,
analog_enabled: false, "solar_maxflow": 30,
pbutton_gpio: 0, "board_profile": "E32V2",
board_profile: 'S32', "fahrenheit": false,
bool_format: 1, "bool_format": 1,
bool_dashboard: 1, "bool_dashboard": 1,
enum_format: 1, "enum_format": 1,
fahrenheit: false "weblog_level": 6,
"weblog_buffer": 50,
"weblog_compact": true,
"phy_type": 1,
"eth_power": 15,
"eth_phy_addr": 0,
"eth_clock_mode": 1,
"platform": "ESP32R",
"modbus_enabled": false,
"modbus_port": 502,
"modbus_max_clients": 10,
"modbus_timeout": 10000
}; };
const emsesp_devices = { const emsesp_devices = {

View File

@@ -26,7 +26,7 @@ uuid::log::Logger Command::logger_{F_(command), uuid::log::Facility::DAEMON};
std::vector<Command::CmdFunction> Command::cmdfunctions_; std::vector<Command::CmdFunction> Command::cmdfunctions_;
// takes a path and a json body, parses the data and calls the command // takes a URI path and a json body, parses the data and calls the command
// the path is leading so if duplicate keys are in the input JSON it will be ignored // the path is leading so if duplicate keys are in the input JSON it will be ignored
// the entry point will be either via the Web API (api/) or MQTT (<base>/) // the entry point will be either via the Web API (api/) or MQTT (<base>/)
// returns a return code and json output // returns a return code and json output
@@ -34,22 +34,11 @@ uint8_t Command::process(const char * path, const bool is_admin, const JsonObjec
SUrlParser p; // parse URL for the path names SUrlParser p; // parse URL for the path names
p.parse(path); p.parse(path);
if (!p.paths().size()) { // check first if it's from API or MQTT, if so strip the "api/" or "<base>/" from the path
return json_message(CommandRet::ERROR, "invalid path", output); if (p.paths().size() && ((p.paths().front() == "api") || (p.paths().front() == Mqtt::base()))) {
}
// check first if it's from API, if so strip the "api/"
if (p.paths().front() == "api") {
p.paths().erase(p.paths().begin()); p.paths().erase(p.paths().begin());
} else { } else {
// not /api, so must be MQTT path. Check for base and remove it. return json_message(CommandRet::ERROR, "invalid path", output, path); // error
if (!strncmp(path, Mqtt::base().c_str(), Mqtt::base().length())) {
char new_path[Mqtt::MQTT_TOPIC_MAX_SIZE];
strlcpy(new_path, path, sizeof(new_path));
p.parse(new_path + Mqtt::base().length() + 1); // re-parse the stripped path
} else {
return json_message(CommandRet::ERROR, "unrecognized path", output); // error
}
} }
// re-calculate new path // re-calculate new path
@@ -701,15 +690,21 @@ void Command::show_all(uuid::console::Shell & shell) {
shell.println(); shell.println();
} }
uint8_t Command::json_message(uint8_t error_code, const char * message, const JsonObject output) { // creates a single json document with an error message
// object is optional
uint8_t Command::json_message(uint8_t error_code, const char * message, const JsonObject output, const char * object) {
output.clear(); output.clear();
if (object) {
output["message"] = std::string(message) + " " + object;
} else {
output["message"] = message; output["message"] = message;
}
return error_code; return error_code;
} }
// // **************************
// SUrlParser class // **** SUrlParser class ****
// // **************************
// Extract only the path component from the passed URI and normalized it // Extract only the path component from the passed URI and normalized it
// e.g. //one/two////three/// becomes /one/two/three // e.g. //one/two////three/// becomes /one/two/three

View File

@@ -143,7 +143,7 @@ class Command {
static std::vector<CmdFunction> cmdfunctions_; // the list of commands static std::vector<CmdFunction> cmdfunctions_; // the list of commands
static uint8_t json_message(uint8_t error_code, const char * message, const JsonObject output); static uint8_t json_message(uint8_t error_code, const char * message, JsonObject output, const char * object = nullptr);
}; };
class SUrlParser { class SUrlParser {

View File

@@ -580,7 +580,7 @@ static void setup_commands(std::shared_ptr<Commands> & commands) {
return; return;
} else if (!has_data) { } else if (!has_data) {
// show message if no data returned (e.g. for analogsensor, temperaturesensor, custom) // show message if no data returned (e.g. for analogsensor, temperaturesensor, custom)
shell.println("Command executed. Check log for messages."); shell.println("Command executed");
return; return;
} else { } else {
return; return;

View File

@@ -438,7 +438,7 @@ ModbusMessage Modbus::handleWrite(const ModbusMessage & request) {
if (output.size()) { if (output.size()) {
snprintf(error, snprintf(error,
sizeof(error), sizeof(error),
"Modbus write command failed with error: %s (%s)", "Modbus write command failed with error %s (%s)",
(const char *)output["message"], (const char *)output["message"],
Command::return_code_string(return_code)); Command::return_code_string(return_code));
} else { } else {

View File

@@ -228,9 +228,9 @@ void Mqtt::on_message(const char * topic, const uint8_t * payload, size_t len) {
#if defined(EMSESP_DEBUG) #if defined(EMSESP_DEBUG)
if (len) { if (len) {
LOG_DEBUG("Received topic `%s` => payload `%s` (length %d)", topic, message, len); LOG_DEBUG("Received topic %s => payload '%s' (length %d)", topic, message, len);
} else { } else {
LOG_DEBUG("Received topic `%s`", topic); LOG_DEBUG("Received topic %s", topic);
} }
#endif #endif
// remove HA topics if we don't use discovery // remove HA topics if we don't use discovery

View File

@@ -1172,7 +1172,9 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
test("boiler"); test("boiler");
test("thermostat"); test("thermostat");
EMSESP::mqtt_.incoming("ems-esp/boiler/wwseltemp", "59"); EMSESP::mqtt_.incoming("ems-esp/boiler/seltemp", "59");
EMSESP::mqtt_.incoming("badems-esp/boiler/seltemp", "59"); // should fail
ok = true; ok = true;
} }

View File

@@ -32,7 +32,6 @@ WebSettingsService::WebSettingsService(AsyncWebServer * server, FS * fs, Securit
} }
void WebSettings::read(WebSettings & settings, JsonObject root) { void WebSettings::read(WebSettings & settings, JsonObject root) {
root["version"] = settings.version;
root["locale"] = settings.locale; root["locale"] = settings.locale;
root["tx_mode"] = settings.tx_mode; root["tx_mode"] = settings.tx_mode;
root["ems_bus_id"] = settings.ems_bus_id; root["ems_bus_id"] = settings.ems_bus_id;

View File

@@ -24,9 +24,9 @@
namespace emsesp { namespace emsesp {
// /rest/HardwareStatus // /rest/hardwareStatus
WebStatusService::WebStatusService(AsyncWebServer * server, SecurityManager * securityManager) { WebStatusService::WebStatusService(AsyncWebServer * server, SecurityManager * securityManager) {
server->on(HARDWARE_STATUS_SERVICE_PATH, HTTP_GET, [this](AsyncWebServerRequest * request) { HardwareStatus(request); }); server->on(HARDWARE_STATUS_SERVICE_PATH, HTTP_GET, [this](AsyncWebServerRequest * request) { hardwareStatus(request); });
server->on(SYSTEM_STATUS_SERVICE_PATH, HTTP_GET, [this](AsyncWebServerRequest * request) { systemStatus(request); }); server->on(SYSTEM_STATUS_SERVICE_PATH, HTTP_GET, [this](AsyncWebServerRequest * request) { systemStatus(request); });
} }
@@ -85,7 +85,7 @@ void WebStatusService::systemStatus(AsyncWebServerRequest * request) {
request->send(response); request->send(response);
} }
void WebStatusService::HardwareStatus(AsyncWebServerRequest * request) { void WebStatusService::hardwareStatus(AsyncWebServerRequest * request) {
EMSESP::system_.refreshHeapMem(); // refresh free heap and max alloc heap EMSESP::system_.refreshHeapMem(); // refresh free heap and max alloc heap
auto * response = new AsyncJsonResponse(false); auto * response = new AsyncJsonResponse(false);
@@ -121,6 +121,7 @@ void WebStatusService::HardwareStatus(AsyncWebServerRequest * request) {
root["fs_free"] = EMSESP::system_.FStotal() - FSused; root["fs_free"] = EMSESP::system_.FStotal() - FSused;
root["free_caps"] = heap_caps_get_free_size(MALLOC_CAP_8BIT) / 1024; // includes heap and psram root["free_caps"] = heap_caps_get_free_size(MALLOC_CAP_8BIT) / 1024; // includes heap and psram
root["psram"] = EMSESP::system_.PSram();
if (EMSESP::system_.PSram()) { if (EMSESP::system_.PSram()) {
root["psram_size"] = EMSESP::system_.PSram(); root["psram_size"] = EMSESP::system_.PSram();
root["free_psram"] = ESP.getFreePsram() / 1024; root["free_psram"] = ESP.getFreePsram() / 1024;

View File

@@ -1,7 +1,7 @@
#ifndef WebStatusService_h #ifndef WebStatusService_h
#define WebStatusService_h #define WebStatusService_h
#define HARDWARE_STATUS_SERVICE_PATH "/rest/HardwareStatus" #define HARDWARE_STATUS_SERVICE_PATH "/rest/hardwareStatus"
#define SYSTEM_STATUS_SERVICE_PATH "/rest/systemStatus" #define SYSTEM_STATUS_SERVICE_PATH "/rest/systemStatus"
namespace emsesp { namespace emsesp {
@@ -12,7 +12,7 @@ class WebStatusService {
private: private:
void systemStatus(AsyncWebServerRequest * request); void systemStatus(AsyncWebServerRequest * request);
void HardwareStatus(AsyncWebServerRequest * request); void hardwareStatus(AsyncWebServerRequest * request);
}; };
} // namespace emsesp } // namespace emsesp