diff --git a/code/espurna/button.cpp b/code/espurna/button.cpp index 7e59196c..39f57448 100644 --- a/code/espurna/button.cpp +++ b/code/espurna/button.cpp @@ -25,6 +25,9 @@ Copyright (C) 2019-2021 by Maxim Prokhorov @@ -112,6 +115,8 @@ PROGMEM_STRING(MqttRetain, "btnMqttRetain"); [[gnu::unused]] PROGMEM_STRING(AnalogLevel, "btnLevel"); +[[gnu::unused]] PROGMEM_STRING(TerminalCommand, "btnTermCmd"); + } // namespace } // namespace keys @@ -181,6 +186,8 @@ PROGMEM_STRING(Custom, "custom"); [[gnu::unused]] PROGMEM_STRING(FanMedium, "fan-medium"); [[gnu::unused]] PROGMEM_STRING(FanHigh, "fan-high"); +PROGMEM_STRING(TerminalCommand, "term-cmd"); + static constexpr Enumeration ButtonActionOptions[] PROGMEM { {ButtonAction::None, None}, #if RELAY_SUPPORT @@ -204,6 +211,9 @@ static constexpr Enumeration ButtonActionOptions[] PROGMEM { {ButtonAction::FanMedium, FanMedium}, {ButtonAction::FanHigh, FanHigh}, #endif +#if TERMINAL_SUPPORT + {ButtonAction::TerminalCommand, TerminalCommand}, +#endif }; } // namespace @@ -733,6 +743,12 @@ int analogLevel(size_t index) { } #endif +#if TERMINAL_SUPPORT +String terminalCommand(size_t index) { + return getSetting({keys::TerminalCommand, index}); +} +#endif + } // namespace namespace query { @@ -801,6 +817,9 @@ static constexpr espurna::settings::query::IndexedSetting IndexedSettings[] PROG {keys::MqttSendAll, internal::mqttSendAllEvents}, {keys::MqttRetain, internal::mqttRetain}, #endif +#if TERMINAL_SUPPORT + {keys::TerminalCommand, settings::terminalCommand}, +#endif }; bool checkSamePrefix(StringView key) { @@ -824,6 +843,31 @@ void setup() { } // namespace settings namespace terminal { +namespace internal { + +void inject(String command) { + if (!command.endsWith("\r\n") && !command.endsWith("\n")) { + command.concat('\n'); + } + + static EphemeralPrint output; + PrintString error(64); + + if (!espurna::terminal::api_find_and_call(command, output, error)) { + DEBUG_MSG_P(PSTR("[BUTTON] \"%s\"\n"), error.c_str()); + } +} + +} // namespace internal + +void process(size_t id) { + auto cmd = settings::terminalCommand(id); + if (!cmd.length()) { + return; + } + + internal::inject(std::move(cmd)); +} void button(::terminal::CommandContext&& ctx) { if (ctx.argv.size() == 2) { @@ -854,6 +898,10 @@ static constexpr ::terminal::Command Commands[] PROGMEM { {Button, button}, }; +void setup() { + espurna::terminal::add(Commands); +} + } // namespace terminal } // namespace button } // namespace espurna @@ -1181,6 +1229,11 @@ void buttonEvent(size_t id, ButtonEvent event) { #endif break; + case ButtonAction::TerminalCommand: +#if TERMINAL_SUPPORT + espurna::button::terminal::process(id); +#endif + case ButtonAction::None: break; @@ -1495,7 +1548,7 @@ void buttonSetup() { DEBUG_MSG_P(PSTR("[BUTTON] Number of buttons: %u\n"), count); #if TERMINAL_SUPPORT - espurna::terminal::add(espurna::button::terminal::Commands); + espurna::button::terminal::setup(); #endif if (count) { diff --git a/code/espurna/button.h b/code/espurna/button.h index c28cc43e..c4e56622 100644 --- a/code/espurna/button.h +++ b/code/espurna/button.h @@ -48,6 +48,7 @@ enum class ButtonAction { FanLow, FanMedium, FanHigh, + TerminalCommand, }; using ButtonEventHandler = void(*)(size_t id, ButtonEvent event); diff --git a/code/espurna/config/types.h b/code/espurna/config/types.h index c8adb529..58913949 100644 --- a/code/espurna/config/types.h +++ b/code/espurna/config/types.h @@ -17,23 +17,24 @@ // BUTTONS //------------------------------------------------------------------------------ -#define BUTTON_ACTION_NONE ButtonAction::None -#define BUTTON_ACTION_TOGGLE ButtonAction::Toggle -#define BUTTON_ACTION_ON ButtonAction::On -#define BUTTON_ACTION_OFF ButtonAction::Off -#define BUTTON_ACTION_AP ButtonAction::AccessPoint -#define BUTTON_ACTION_RESET ButtonAction::Reset -#define BUTTON_ACTION_PULSE ButtonAction::Pulse -#define BUTTON_ACTION_FACTORY ButtonAction::FactoryReset -#define BUTTON_ACTION_WPS ButtonAction::Wps -#define BUTTON_ACTION_SMART_CONFIG ButtonAction::SmartConfig -#define BUTTON_ACTION_DIM_UP ButtonAction::BrightnessIncrease -#define BUTTON_ACTION_DIM_DOWN ButtonAction::BrightnessDecrease -#define BUTTON_ACTION_DISPLAY_ON ButtonAction::DisplayOn -#define BUTTON_ACTION_CUSTOM ButtonAction::Custom -#define BUTTON_ACTION_FAN_LOW ButtonAction::FanLow -#define BUTTON_ACTION_FAN_MEDIUM ButtonAction::FanMedium -#define BUTTON_ACTION_FAN_HIGH ButtonAction::FanHigh +#define BUTTON_ACTION_NONE ButtonAction::None +#define BUTTON_ACTION_TOGGLE ButtonAction::Toggle +#define BUTTON_ACTION_ON ButtonAction::On +#define BUTTON_ACTION_OFF ButtonAction::Off +#define BUTTON_ACTION_AP ButtonAction::AccessPoint +#define BUTTON_ACTION_RESET ButtonAction::Reset +#define BUTTON_ACTION_PULSE ButtonAction::Pulse +#define BUTTON_ACTION_FACTORY ButtonAction::FactoryReset +#define BUTTON_ACTION_WPS ButtonAction::Wps +#define BUTTON_ACTION_SMART_CONFIG ButtonAction::SmartConfig +#define BUTTON_ACTION_DIM_UP ButtonAction::BrightnessIncrease +#define BUTTON_ACTION_DIM_DOWN ButtonAction::BrightnessDecrease +#define BUTTON_ACTION_DISPLAY_ON ButtonAction::DisplayOn +#define BUTTON_ACTION_CUSTOM ButtonAction::Custom +#define BUTTON_ACTION_FAN_LOW ButtonAction::FanLow +#define BUTTON_ACTION_FAN_MEDIUM ButtonAction::FanMedium +#define BUTTON_ACTION_FAN_HIGH ButtonAction::FanHigh +#define BUTTON_ACTION_TERMINAL_COMMAND ButtonAction::TerminalCommand // Deprecated: legacy mapping, changed to action from above #define BUTTON_MODE_NONE BUTTON_ACTION_NONE diff --git a/code/espurna/ir.cpp b/code/espurna/ir.cpp index 1b208a68..1ac720a5 100644 --- a/code/espurna/ir.cpp +++ b/code/espurna/ir.cpp @@ -29,6 +29,9 @@ $ pio run -e ... \ #include "relay.h" #include "terminal.h" +#include "libs/EphemeralPrint.h" +#include "libs/PrintString.h" + #include #include #include @@ -1518,24 +1521,15 @@ Preset preset() { namespace internal { -struct EphemeralPrint : public Print { - size_t write(uint8_t) override { - return 0; - } - - size_t write(const uint8_t*, size_t) override { - return 0; - } -}; - void inject(String command) { if (!command.endsWith("\r\n") && !command.endsWith("\n")) { command.concat('\n'); } static EphemeralPrint output; - if (!espurna::terminal::api_find_and_call(command, output)) { - DEBUG_MSG_P(PSTR("[IR] Failed to execute command: \"%s\"\n"), command.c_str()); + PrintString error(64); + if (!espurna::terminal::api_find_and_call(command, output, error)) { + DEBUG_MSG_P(PSTR("[IR] \"%s\"\n"), error.c_str()); } } diff --git a/code/espurna/libs/EphemeralPrint.h b/code/espurna/libs/EphemeralPrint.h new file mode 100644 index 00000000..d0fdbeaf --- /dev/null +++ b/code/espurna/libs/EphemeralPrint.h @@ -0,0 +1,22 @@ +/* + +Arduino Print without any buffer. + +*/ + +#pragma once + +#include + +#include +#include + +struct EphemeralPrint : public Print { + size_t write(uint8_t) override { + return 0; + } + + size_t write(const uint8_t*, size_t) override { + return 0; + } +};