{"id":13831386,"url":"https://github.com/SpacehuhnTech/SimpleCLI","last_synced_at":"2025-07-09T13:33:39.843Z","repository":{"id":46022555,"uuid":"131738846","full_name":"SpacehuhnTech/SimpleCLI","owner":"SpacehuhnTech","description":"Command Line Interface Library for Arduino","archived":false,"fork":false,"pushed_at":"2022-06-14T21:04:47.000Z","size":483,"stargazers_count":312,"open_issues_count":6,"forks_count":55,"subscribers_count":22,"default_branch":"master","last_synced_at":"2025-05-19T12:07:02.373Z","etag":null,"topics":["arduino","cli","command","interface","library","line"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SpacehuhnTech.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"github":"spacehuhntech","patreon":null,"open_collective":null,"ko_fi":"spacehuhn","tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"custom":["spacehuhn.com/store/"]}},"created_at":"2018-05-01T16:55:27.000Z","updated_at":"2025-05-04T19:42:01.000Z","dependencies_parsed_at":"2022-08-12T12:40:24.589Z","dependency_job_id":null,"html_url":"https://github.com/SpacehuhnTech/SimpleCLI","commit_stats":null,"previous_names":[],"tags_count":15,"template":false,"template_full_name":null,"purl":"pkg:github/SpacehuhnTech/SimpleCLI","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SpacehuhnTech%2FSimpleCLI","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SpacehuhnTech%2FSimpleCLI/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SpacehuhnTech%2FSimpleCLI/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SpacehuhnTech%2FSimpleCLI/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SpacehuhnTech","download_url":"https://codeload.github.com/SpacehuhnTech/SimpleCLI/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SpacehuhnTech%2FSimpleCLI/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":264468241,"owners_count":23613062,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["arduino","cli","command","interface","library","line"],"created_at":"2024-08-04T10:01:26.802Z","updated_at":"2025-07-09T13:33:39.440Z","avatar_url":"https://github.com/SpacehuhnTech.png","language":"C++","readme":"# SimpleCLI\n\n\u003cp align=\"center\"\u003e\u003cimg alt=\"SimpleCLI Logo\" src=\"img/simplecli.gif\" width=\"150\"\u003e\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n\u003cb\u003eA Command Line Interface Library for Arduino!\u003c/b\u003e\u003cbr\u003e\nAdd commands to your project without hassle.\u003cbr\u003e\n\u003cbr\u003e\n\u003ca href=\"https://www.ardu-badge.com/SimpleCLI\" target=\"_blank\"\u003e\u003cimg alt=\"Ardu Badge for SimpleCLI Library\" src=\"https://www.ardu-badge.com/badge/SimpleCLI.svg\"\u003e\u003c/a\u003e\u003cbr\u003e\n\u003cbr\u003e\n\u003ca href='https://ko-fi.com/G2G75FA4V' target='_blank'\u003e\u003cimg height='36' style='border:0px;height:36px;' src='https://cdn.ko-fi.com/cdn/kofi3.png?v=3' border='0' alt='Buy Me a Coffee at ko-fi.com' /\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n![Cowsay command example](img/cowsay.gif)  \n\n## Projects\nA list of projects that make use of this library:  \n- [Control ESP32 with Command Line Interface Over the Internet](https://www.hackster.io/donowak/control-esp32-with-command-line-interface-over-the-internet-fa9634)\n- [WiFiDuck](https://github.com/spacehuhn/WiFiDuck)\n- [ESP8266 Deauther V3](https://github.com/SpacehuhnTech/esp8266_deauther/tree/v3)\n\n## Overview\n\n- [About](#about)\n- [Supported Devices](#supported-devices)\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Examples](#examples)\n  - [Include Library](#include-library)\n  - [Create SimpleCLI instance](#create-simplecli-instance)\n  - [Adding Commands](#adding-commands)\n  - [Adding Commands with callback](#adding-commands-with-callback)\n  - [Adding Arguments](#adding-arguments)\n  - [Templates](#templates)\n  - [Parsing Input](#parsing-input)\n  - [Reacting on Commands](#reacting-on-commands)\n  - [Reacting on Errors](#reacting-on-errors)\n- [Classes \u0026 Methods](#classes--methods)\n  - [SimpleCLI](#simplecli)\n  - [CommandType](#commandtype)\n  - [Command](#command)\n  - [CommandErrorType](#commanderrortype)\n  - [CommandError](#commanderror)\n  - [ArgumentType](#argumenttype)\n  - [Argument](#argument)\n- [License](#license)\n\n## About\nThe goal of this library is to control your Arduino projects using commands similar to the Linux CLI.  \nBecause parsing and validating strings in C/C++ can be quite a pain, this library aims to simplify the process as much as possible.  \n\n## Supported Devices\nStrings take up a good amount of memory, so **it's strongly recommended to chose a development board with at least 32 KB RAM**.  \nIt doesn't make much sense to run this library on an Uno or Nano, because it will quickly take up a most of the resources.  \nHere's a list of tested hardware (feel free to contribute by making a Pull-Request):  \n\n| Chipset | Board(s) | Flash | RAM | Support |\n| ------- | -------- | ----- | --- | ------- |\n| ATtiny85 | Digispark | 8 KB | 512 Byte | No! (Does not compile C++11) |\n| ATmega328P | Arduino Nano, Arduino Uno | 32 KB | 2 KB | Works for small projects |\n| ATmega32u4 | Arduino Leonardo, Pro Micro | 32 KB | 2,560 Byte | Works for small projects |\n| ATSAMD21G18 | Arduino MKR WiFi 1010 | 256 KB | 32 KB | Yes! |\n| ATSAMD51G19 | Adafruit ItsyBitsy M4 Express | 512 KB | 192 KB | Yes! |\n| ESP8266 | NodeMCU, D1 Mini | 512 KB - 16 MB | 80 KB | Yes! |\n| ESP32 | DSTIKE D-duino-32 | 1 MB - 16 MB |520 KB | Yes! |\n\n*Some flash and RAM values depend on the development board or module being used.*\n\n## Installation\n\n1) Click [Download Zip](https://github.com/spacehuhn/SimpleCLI/archive/master.zip) to download the source code from GitHub.  \n2) Unzip and rename the Folder name to \"SimpleCLI\".  \n3) Paste it in your library folder (usually located somewhere at documents/Arduino/libraries).  \n4) Restart the Arduino IDE.  \n\n## Usage\n\n[![SimpleCLI YouTube Tutorial](https://img.youtube.com/vi/UyW-wICdnKo/0.jpg)](https://www.youtube.com/watch?v=UyW-wICdnKo)\n\n### Examples\n\nPlease check out the [example sketches](https://github.com/spacehuhn/SimpleCLI/tree/master/examples/), it's the quickest way to understand how this library works.  \nThe following sections are for reference.  \n\n![Ping with arguments command example](img/ping.gif)  \n\n### Include Library\n\n```c++\n#include \u003cSimpleCLI.h\u003e\n```\n\n### Create SimpleCLI instance\n\n```c++\nSimpleCLI cli;\n\nSimpleCLI cli(COMMAND_QUEUE_SIZE, ERROR_QUEUE_SIZE);\n```\n\n`COMMAND_QUEUE_SIZE` and `ERROR_QUEUE_SIZE` are `int`s set to 10 commands and 10 errors by default.  \nThe oldest command or error will be deleted automatically if the queue gets full.  \nYou can most likely ignore the queue sizes, as those are just a safety mechanism and won't be important for most use cases.  \n\n### Adding Commands\n\nCommand names should only contain upper-, lowercase letters and numbers!  \nRecommended are names with only lowercase letters and no numbers.  \n\n```c++\n// Normal command with a defined number of arguments\n// For example: echo -str \"Hello\" -n 3\nCommand myCommand = cli.addCommand(\"myCommandName\");\nCommand myCommand = cli.addCmd(\"myCmdName\");\n\n// Single-Argument-Command that saves everything after the command name in the first argument\n// For example: echo this will be a single string -even with hyphen and in \"quotes\"\n// =\u003e \"this will be a single string -even with hyphen and in \"quotes\\\"\" will be the argument value\nCommand mySingleArgumentCommand = cli.addSingleArgumentCommand(\"mySingleArgumentCommandName\");\nCommand mySingleArgCmd = cli.addSingleArgCmd(\"mySingleArgCmdName\");\n\n// Boundless-Command that accepts any amount of arguments separated by spaces\n// For example: sum 1 2 3\n// =\u003e \"1\", \"2\", \"3\" will the argument values\nCommand myBoundlessCommand = cli.addBoundlessCommand(\"myBoundlessCommandName\");\nCommand myBoundlessCmd = cli.addBoundlessCmd(\"myBoundlessCmdName\");\n```\n\n### Adding Commands with callback\n\nSometimes it's useful to give the command a callback function that will be executed automatically when the command was entered.  \nYou must define these callback functions as a global void function with a `cmd` pointer as shown here:  \n```c++\nvoid myCallback(cmd* commandPointer) {\n  Command cmd(commandPointer); // Create wrapper class instance for the pointer\n  // ..\n}\n```\n\nNow you can create a command and pass it the function pointer:  \n```c++\nCommand myCommand = cli.addCommand(\"myCommandName\", myCallback);\nCommand myCommand = cli.addBoundlessCommand(\"myCommandName\", myCallback);\nCommand myCommand = cli.addSingleArgumentCommand(\"myCommandName\", myCallback);\n\nCommand myCommand = cli.addCmd(\"myCommandName\", myCallback);\nCommand myCommand = cli.addBoundlessCmd(\"myCommandName\", myCallback);\nCommand myCommand = cli.addSingleArgCmd(\"myCommandName\", myCallback);\n```\n\n### Adding Arguments\n\nKeep in mind that you can only add arguments to `Command`s and **not** to `SingleArgumentCommand`s and `BoundlessCommand`s.  \n\n```c++\n// myCommandName -argumentName \"argumentValue\"\nArgument myArg = myCommand.addArgument(\"argumentName\");\nArgument myArg = myCommand.addArg(\"argumentName\");\n\n// Giving the argument a default value, means that the user does not have to specify the argument\n// myCommandName\n// myCommandName -argumentName \"argumentValue\"\nArgument myArg = myCommand.addArgument(\"argumentName\", \"DefaultValue\");\nArgument myArg = myCommand.addArg(\"argumentName\", \"DefaultValue\");\n\n\n// Positional arguments have a certain position and do not have to be named\n// myCommandName \"argumentValue\"\n// myCommandName -argumentName \"argumentValue\"\nArgument myArg = myCommand.addPositionalArgument(\"argumentName\");\nArgument myArg = myCommand.addPosArg(\"argumentName\");\n\n// Those can also have default values\n// myCommandName\n// myCommandName \"argumentValue\"\n// myCommandName -argumentName \"argumentValue\"\nArgument myArg = myCommand.addPositionalArgument(\"argumentName\", \"DefaultValue\");\nArgument myArg = myCommand.addPosArg(\"argumentName\", \"DefaultValue\");\n\n\n// Flag arguments can either be specified (set) or not, but they don't accept any value\n// myCommandName\n// myCommandName -argumentName\nArgument myArg = myCommand.addFlagArgument(\"argumentName\");\nArgument myArg = myCommand.addFlagArg(\"argumentName\");\n````\n\n### Templates\n\nWith this neat feature, you can give commands and arguments multiple names.  \n- A comma (`,`) separates multiple names.  \n- A forward slash (`/`) declares everything after it optional (until the next comma, or the end of the string).  \n\nYou can combine them together.  \n\n**This means a command or argument name should not use `,` and `/` as a part of the regular name!**  \nThese characters will always be interpreted as a separator.  \n\nHere are some examples:  \n\n| Name-String | Results |\n| ----------- | ------- |\n| `a,b,c,d,efg` | `a`, `b`, `c`, `d`, `efg` |\n| `ping,pong,test` | `ping`, `pong`, `test` |\n| `p/ping` | `p`, `ping` |\n| `p/ing/s` | `p`, `ping`, `pings` |\n| `p/ing/s,pong` | `p`, `ping`, `pings`, `pong` |\n| `p/ing/s,pong/s` | `p`, `ping`, `pings`, `pong`, `pongs` |\n\n### Parsing Input\n\n```c++\n// Inline\ncli.parse(\"myCommand\");\n\n// From string\nString input = \"myCommand\";\ncli.parse(input);\n\n// From serial\nString input = Serial.readString();\ncli.parse(input);\n```\n\n### Reacting on Commands\n\nBe aware that this is only necessary if you have commands that do not have a callback function.  \nCallbacks will be run automatically and the command will not wait in the queue.  \n```c++\n// First check if a newly parsed command is available\nif(cli.available()) {\n\n  // Get the command out of the queue\n  Command cmd = cli.getCommand();\n\n  // Check if it's the command you're looking for\n  if(cmd == myCommand) {\n\n    // Get the Argument(s) you want\n    Argument myArgument = cmd.getArgument(\"argumentName\"); // via name\n    Argument myOtherArgument = cmd.getArgument(2); // via index\n\n    // Do stuff\n    // ...\n  }\n\n}\n```\n\n### Reacting on Errors\n\n```c++\n// Check if a new error occurred\nif(cli.errored()) {\n  CommandError e = cli.getError();\n\n  // Print the error, or do whatever you want with it\n  Serial.println(e.toString());\n}\n```\n\nYou can also make a error callback function, like this one:  \n\n```c++\nvoid errorCallback(cmd_error* e) {\n    CommandError cmdError(e); // Create wrapper object\n\n    // Print error\n    Serial.print(\"ERROR: \");\n    Serial.println(cmdError.toString());\n\n    // Print command usage\n    if (cmdError.hasCommand()) {\n        Serial.print(\"Did you mean \\\"\");\n        Serial.print(cmdError.getCommand().toString());\n        Serial.println(\"\\\"?\");\n    }\n}\n```\n\nJust don't forget to add the error callback function to the SimpleCLI instance:  \n\n```c++\ncli.setOnError(errorCallback);\n```\n\n## Classes \u0026 Methods\n\nHere is a plain overview of all classes and their methods:  \n\n### SimpleCLI\n\n```c++\nSimpleCLI(int commandQueueSize = 10, int errorQueueSize = 10);\n\nvoid pause();\nvoid unpause();\n\nvoid parse(String\u0026 input);\nvoid parse(const char* input);\nvoid parse(const char* input, size_t input_len);\n\nbool available() const;\nbool errored() const;\nbool paused() const;\n\nint countCmdQueue() const;\nint countErrorQueue() const;\n\nCommand getCmd();\nCommand getCmd(String name);\nCommand getCmd(const char* name);\n\nCommand getCommand();\nCommand getCommand(String name);\nCommand getCommand(const char* name);\n\nCommandError getError();\n\nCommand addCmd(const char* name, void (* callback)(cmd* c)          = NULL);\nCommand addBoundlessCmd(const char* name, void (* callback)(cmd* c) = NULL);\nCommand addSingleArgCmd(const char* name, void (* callback)(cmd* c) = NULL);\n\nCommand addCommand(const char* name, void (* callback)(cmd* c)               = NULL);\nCommand addBoundlessCommand(const char* name, void (* callback)(cmd* c)      = NULL);\nCommand addSingleArgumentCommand(const char* name, void (* callback)(cmd* c) = NULL);\n\nString toString(bool descriptions          = true) const;\nvoid toString(String\u0026 s, bool descriptions = true) const;\n\nvoid setCaseSensetive(bool caseSensetive = true);\nvoid setOnError(void (* onError)(cmd_error* e));\n```\n\n### CommandType\n\n```c++\nenum class CommandType { NORMAL, BOUNDLESS, SINGLE };\n```\n\n### Command\n\n```c++\nCommand(cmd* cmdPointer = NULL, bool persistent = COMMAND_PERSISTENT);\nCommand(const Command\u0026 c);\nCommand(Command\u0026\u0026 c);\n\nCommand\u0026 operator=(const Command\u0026 c);\nCommand\u0026 operator=(Command\u0026\u0026 c);\n\nbool operator==(const Command\u0026 c) const;\nbool operator!=(const Command\u0026 c) const;\n\noperator bool() const;\n\nbool setCaseSensetive(bool caseSensetive = true);\nbool setCallback(void (* callback)(cmd* c));\n\nvoid setDescription(const char* description);\n\nArgument addArg(const char* name, const char* defaultValue);\nArgument addArg(const char* name);\nArgument addPosArg(const char* name, const char* defaultValue);\nArgument addPosArg(const char* name);\nArgument addFlagArg(const char* name, const char* defaultValue = \"\");\n\nArgument addArgument(const char* name, const char* defaultValue);\nArgument addArgument(const char* name);\nArgument addPositionalArgument(const char* name, const char* defaultValue);\nArgument addPositionalArgument(const char* name);\nArgument addFlagArgument(const char* name, const char* defaultValue = \"\");\n\nbool equals(String name) const;\nbool equals(const char* name) const;\nbool equals(const Command\u0026 c) const;\n\nString getName() const;\nint countArgs() const;\n\nArgument getArgument(int i = 0) const;\nArgument getArgument(const char* name) const;\nArgument getArgument(String name) const;\nArgument getArgument(const Argument\u0026 a) const;\n\nArgument getArg(int i = 0) const;\nArgument getArg(const char* name) const;\nArgument getArg(String name) const;\nArgument getArg(const Argument\u0026 a) const;\n\nCommandType getType() const;\n\nbool hasDescription() const;\nString getDescription() const;\n\nString toString(bool description          = true) const;\nvoid toString(String\u0026 s, bool description = true) const;\n\nvoid run() const;\n\ncmd* getPtr();\n```\n\n### CommandErrorType\n\n```c++\nenum class CommandErrorType { NULL_POINTER, EMPTY_LINE, PARSE_SUCCESSFUL,\n                              COMMAND_NOT_FOUND, UNKNOWN_ARGUMENT, MISSING_ARGUMENT,\n                              MISSING_ARGUMENT_VALUE, UNCLOSED_QUOTE };\n```\n\n### CommandError\n\n```c++\nCommandError(cmd_error* errorPointer = NULL, bool persistent = COMMAND_ERROR_PERSISTENT);\nCommandError(const CommandError\u0026 e);\nCommandError(CommandError\u0026\u0026 e);\n\nCommandError\u0026 operator=(const CommandError\u0026 e);\nCommandError\u0026 operator=(CommandError\u0026\u0026 e);\n\nbool operator==(const CommandError\u0026 e) const;\nbool operator!=(const CommandError\u0026 e) const;\n\nbool operator\u003e(const CommandError\u0026 e) const;\nbool operator\u003c(const CommandError\u0026 e) const;\n\nbool operator\u003e=(const CommandError\u0026 e) const;\nbool operator\u003c=(const CommandError\u0026 e) const;\n\noperator bool() const;\n\nbool hasCommand() const;\nbool hasArgument() const;\nbool hasData() const;\n\nbool hasCmd() const;\nbool hasArg() const;\n\nCommandErrorType getType() const;\nCommand getCommand() const;\nArgument getArgument() const;\nString getData() const;\nString getMessage() const;\n\nCommand getCmd() const;\nArgument getArg() const;\nString getMsg() const;\n\nString toString() const;\nvoid toString(String\u0026 s) const;\n\ncmd_error* getPtr();\n```\n\n### ArgumentType\n\n```c++\nenum class ArgumentType { NORMAL, POSITIONAL, FLAG };\n```\n\n### Argument\n\n```c++\nArgument(arg* argPointer = NULL, bool persistent = ARGUMENT_PERSISTENT);\nArgument(const Argument\u0026 a);\nArgument(Argument\u0026\u0026 a);\n\nArgument\u0026 operator=(const Argument\u0026 a);\nArgument\u0026 operator=(Argument\u0026\u0026 a);\n\nbool operator==(const Argument\u0026 a) const;\nbool operator!=(const Argument\u0026 a) const;\n\noperator bool() const;\n\nbool isSet() const;\nbool isRequired() const;\nbool isOptional() const;\nbool hasDefaultValue() const;\n\nbool isReq() const;\nbool isOpt() const;\n\nString getName() const;\nString getValue() const;\n\nArgumentType getType() const;\n\nString toString() const;\nvoid toString(String\u0026 s) const;\n\nbool equals(String name, bool caseSensetive       = false) const;\nbool equals(const char* name, bool caseSensetive  = false) const;\nbool equals(const Argument\u0026 a, bool caseSensetive = false) const;\n\narg* getPtr();\n```\n\n## License\n\nThis software is licensed under the MIT License. See the [license file](LICENSE) for details.  \n","funding_links":["https://github.com/sponsors/spacehuhntech","https://ko-fi.com/spacehuhn","spacehuhn.com/store/","https://ko-fi.com/G2G75FA4V'"],"categories":["C++"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FSpacehuhnTech%2FSimpleCLI","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FSpacehuhnTech%2FSimpleCLI","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FSpacehuhnTech%2FSimpleCLI/lists"}