/* TERMINAL MODULE Copyright (C) 2016-2019 by Xose Pérez Copyright (C) 2020-2022 by Maxim Prokhorov */ #include "espurna.h" #if TERMINAL_SUPPORT #if API_SUPPORT #include "api.h" #endif #if WEB_SUPPORT #include "ws.h" #endif #include "crash.h" #include "mqtt.h" #include "settings.h" #include "system.h" #include "sensor.h" #include "telnet.h" #include "terminal.h" #include "utils.h" #include "wifi.h" #include "libs/PrintString.h" #include #include #include #include // FS 'range', declared at compile time via .ld script PROVIDE declarations // (althought, in recent Core versions, these may be set at runtime) extern "C" uint32_t _FS_start; extern "C" uint32_t _FS_end; #if WEB_SUPPORT #include "web_print.ipp" #endif namespace espurna { namespace terminal { namespace { namespace build { constexpr size_t serialBufferSize() { return TERMINAL_SERIAL_BUFFER_SIZE; } constexpr size_t serialPort() { return TERMINAL_SERIAL_PORT - 1; } } // namespace build // ----------------------------------------------------------------------------- // Commands // ----------------------------------------------------------------------------- namespace commands { PROGMEM_STRING(Commands, "COMMANDS"); PROGMEM_STRING(Help, "HELP"); void help(CommandContext&& ctx) { auto names = terminal::names(); std::sort(names.begin(), names.end(), [](StringView lhs, StringView rhs) { // XXX: Core's ..._P funcs only allow 2nd pointer to be in PROGMEM, // explicitly load the 1st one // TODO: can we just assume linker already sorted all strings? return strncasecmp_P( lhs.toString().begin(), rhs.begin(), lhs.length()) < 0; }); ctx.output.print(F("Available commands:\n")); for (auto name : names) { ctx.output.printf("> %s\n", name.c_str()); } terminalOK(ctx); } PROGMEM_STRING(LightSleep, "SLEEP.LIGHT"); void light_sleep(CommandContext&& ctx) { if (ctx.argv.size() == 2) { using namespace espurna::settings::internal::duration_convert; const auto result = parse(ctx.argv[1], std::micro{}); if (!result.ok) { terminalError(ctx, F("Invalid time")); return; } const auto duration = to_chrono_duration(result.value); if (!instantLightSleep(duration)) { terminalError(ctx, F("Could not sleep")); return; } return; } instantLightSleep(); } PROGMEM_STRING(DeepSleep, "SLEEP.DEEP"); void deep_sleep(CommandContext&& ctx) { if (ctx.argv.size() != 2) { terminalError(ctx, F("SLEEP.DEEP