# REMOTE CONSOLE

Remote console is a unique Thinger.io feature to allow remote access to the devices. It allows the creation of web terminals to interact with the device like in a serial interface. It also provides features to create interactive terminals on any Arduino-compatible device.&#x20;

This feature is especially useful for remote diagnosis, showing logs on devices, managing device configuration, or any other functionality, as the console can be easily extended to include new commands.

![Remote console for IoT devices](https://2241973068-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LpXqB3J1BMD5s4OpYSg%2F-Mka6tDVp3Zoy2uFO-mZ%2F-Mka8FVxpr6RUZkeed2G%2Fiot-terminal.gif?alt=media\&token=9f945094-4840-45d8-934c-3181bafb13f9)

## Web Serial Interface

By default, the Thinger.io Console can work as a web serial interface, similar to the Arduino Serial Monitor, where the device writes logs to the serial interface.&#x20;

To use Thinger.io Console, it is required to include the `ThingerConsole.h` file and create an instance by `thing` reference.

```
#include <ThingerConsole.h>

ThingerConsole console(thing);
```

### Writing to Console

Then it is possible to use the `console` instance for logging to the remote terminal by using the same interface available in the Arduino `Serial` class, i.e, using `println`, `printf`, etc. This code shows a log every second:

```cpp
unsigned long last_log = 0;
void loop() {
  thing.handle();
  auto current = millis();
  
  if(current-last_log>=1000){
    last_log = current;
    console.printf("printing on serial interface: %lu\r\n", current);
  }
}
```

When the terminal is connected in the Thinger.io console, the device will start to send the configured log. If there is no terminal connected to the device, the device will skip sending any data over the wire.

![Writing to Thinger.io web console](https://2241973068-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LpXqB3J1BMD5s4OpYSg%2F-Mka6tDVp3Zoy2uFO-mZ%2F-Mkb-389-7ZWKg21l0ee%2Fwriting_to_web_serial.gif?alt=media\&token=8124527d-c98b-4f6d-952d-95a4e4c39cae)

It is possible to check if the console is connected, so the associated logging code can be omitted, which can be useful if the log involves doing some calculation, reading a sensor, etc. The above example can be improved by adding an extra check&#x20;

```cpp
unsigned long last_log = 0;
void loop() {
  thing.handle();
  
  // check if console is connected
  if(console){
    auto current = millis();
    if(current-last_log>=1000){
      last_log = current;
      console.printf("printing on serial interface: %lu\r\n", current);
    }
  }
}
```

{% hint style="info" %}
If the web console is not connected, the device will not send any data over the wire.
{% endhint %}

### Reading from Console

Reading from the serial can be done in the same way it is done over Arduino `Serial` interface. This code sample checks if there is any data available using the `available` method on the console (in the same way it is used on Arduino `Serial`), and will print back to the console:

```cpp
void loop() {
  thing.handle();
  if(console.available()){
    console.setTimeout(100);
    String input = console.readStringUntil('\n');
    console.print("> I received: ");
    console.println(input);
  }
}
```

![Reading from Thinger.io remote console](https://2241973068-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LpXqB3J1BMD5s4OpYSg%2F-Mkb2IduW9H8oVfFjznh%2F-Mkb7Vs7FcGHrQdioF6f%2Fconsole_read.gif?alt=media\&token=e3bddd98-e081-4e1f-a522-cea1bb58c532)

## Interactive terminals

It is possible to create interactive terminals easily for handling custom commands with arguments. For working with the interactive terminal mode, it is required to create and register commands on the console instance.

### Create Commands

Creating a new command in the console can be done with the `setup` function. It is required to call the function `command` over the `console` instance. This function requires two arguments: the `command name` first and the second `command function`. There is an optional parameters that is the `command description`, that can be useful to specify command arguments or any other help about the command.

In the following sections, some command examples are presented covering different requirements, like writing to the console, reading arguments, or reading from the console.

#### Millis Command Example

The simplest example of a command registers a command named `millis`, and a function that just prints the result of the `millis()` function over the console terminal. It also includes a description in the third argument with this content.

```cpp
void setup() {
  // any other code
  
  // console commands
  console.command("millis", [&](int argc, char* argv[]){
    console.println(millis());
  }, "get current time millis");
}

void loop() {
  thing.handle();
}
```

This will result in a prompt with an interactive terminal in the console, with the ability to execute the `millis` function defined above.

![Millis Command Example](https://2241973068-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LpXqB3J1BMD5s4OpYSg%2F-Mkb2IduW9H8oVfFjznh%2F-MkbMt7bmyXulJtVUIAi%2Fmillis.gif?alt=media\&token=fba2e120-8e83-4372-957e-7f0e83637e3c)

{% hint style="info" %}
The function definition with the syntax `[&](int argc, char* argv[]{}`is a C++ lambda function, but it is possible to use any other`void function(int argc, char* argv[]){}`
{% endhint %}

#### Log Command Example&#x20;

There are some cases where commands need to be running during long periods, i.e., to print an ongoing log. The command will print a sample log until the command is canceled or the console is closed.

```cpp
void setup() {
  console.command("log", [&](int argc, char* argv[]){
      while(console.command_running()){
        console.printf("Running log at %lu\r\n", millis());
        delay(1000);
      }
  }, "show logs");
}
```

To work with long-running commands, it is required to frequently check the `command_running` method, which will return false if the console has been closed or the command was cancelled.

{% hint style="info" %}
To cancel a running command on the terminal, just press Ctrl+C
{% endhint %}

![Log Command Example](https://2241973068-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LpXqB3J1BMD5s4OpYSg%2F-MkbO535Q0qmfEiAixi8%2F-MkbQuTpD8l7HQKN_Q4N%2Fiot_long_command_run.gif?alt=media\&token=8b1fb76f-9f0e-468e-918f-e7422c068406)

#### GPIO Command Example&#x20;

Some commands may need to accept arguments, i.e., turn on/off a given GPIO, print a given string to a display, modify a threshold, etc. For this reason, all commands receive `argc` and `argv` parameters, like in any standard C/C++ main function. `argc` determines the number of arguments, and `argv` is an array of `char*` which holds all parsed parameters. Any command will receive at least one argument, which is the command name.

A command is created to modify the digital state of a given GPIO. This function accepts two parameters, which are the GPIO pin number and the desired state.&#x20;

```cpp
void setup() {
  console.command("gpio", [&](int argc, char* argv[]){
      if(argc<3){
        console.error("missing parameters");
      }else{
        int pin = atoi(argv[1]);
        pinMode(pin, OUTPUT);
        digitalWrite(pin, strcmp(argv[2],"on")==0);
        console.printf("%d turned %sn", pin, argv[2]);
      }
  }, "<pin> <on|off> turn on/off a given gpio");
}
```

![GPIO Command Example](https://2241973068-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LpXqB3J1BMD5s4OpYSg%2F-MkbO535Q0qmfEiAixi8%2F-MkbkaHphrEoOEfg6in9%2F698JdrxVzx.gif?alt=media\&token=2668e2b2-6622-4847-9d4c-0eca9509eb0f)

#### Hello Command Example

Commands may also require reading console inputs interactively while they are running. A simple command is outlined that asks for a name to say hello.

```cpp
void setup() {
  console.command("hello", [&](int argc, char* argv[]){
    console.print("please, enter your name: ");
    console.flush();
    while(console.command_running() && !console.available());
    String name = console.readStringUntil('\n');
    console.printf("hello %s\r\n", name.c_str());
  }, "hello command");
}
```

Once the command is executed, it will prompt the user for its name, waiting until it is ready. After typing the name and pressing Enter,, it will display the name with a hello.

![Interactive Command Example](https://2241973068-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LpXqB3J1BMD5s4OpYSg%2F-MkbyJZsHMRS5nePOE6N%2F-Mkc72J-auL-GbX83AOf%2FO9a763y2z7.gif?alt=media\&token=48be9161-92ff-49ab-adae-1870813f7db0)

### Terminal Prompt

By default, when the interactive terminal is enabled, it will show a prompt with the device identifier. The `esp32` name acts as the device's identifier:

![Default Console Prompt based on the device ID (esp32)](https://2241973068-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LpXqB3J1BMD5s4OpYSg%2F-Mkb2IduW9H8oVfFjznh%2F-MkbBV4Cutm6cYpEoX_m%2Fimage.png?alt=media\&token=e6c756b9-eded-4e42-8238-bf2e1f1fe9f8)

The prompt name can be modified by using the `set_prompt("my prompt")` method on the console instance. For example:

```cpp
void setup(){
    console.set_prompt("Arduino");
}
```

Will result in a modified prompt with the `Arduino` name.

![Custom Prompt](https://2241973068-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LpXqB3J1BMD5s4OpYSg%2F-MkbpHHnp22lzGJI2Vpq%2F-Mkby3DXKCcqLPWVKh5D%2Fimage.png?alt=media\&token=2dbee7f4-84b1-425d-892f-adbe7d212866)

### Default Commands

By default, Thinger.io adds some general utility commands.

#### Help command

The help command will display all registered commands with an associated description.

![Help command to see the registered commands](https://2241973068-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LpXqB3J1BMD5s4OpYSg%2F-MkbyJZsHMRS5nePOE6N%2F-Mkc7wseDK4NHDXTsHa9%2Fimage.png?alt=media\&token=6854a8dc-cae2-454d-bb44-eded41450728)

#### Reboot command

Thinger.io client implements a command that will reboot the device, as in a normal computer.&#x20;

![Reboot command](https://2241973068-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LpXqB3J1BMD5s4OpYSg%2F-Mkb2IduW9H8oVfFjznh%2F-MkbJZ9LCd3ZEq0C6cua%2Fimage.png?alt=media\&token=d100bf10-6de1-45cb-8e06-1dcbb17bc701)

#### Clear command

It can be useful to clear the console sometimes, so it is a clear console command to clear all screen content.

![Clear Command](https://2241973068-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LpXqB3J1BMD5s4OpYSg%2F-MkbyJZsHMRS5nePOE6N%2F-Mkc8aydjcVbHRSdVQh8%2F867dsM52ca.gif?alt=media\&token=1c84087f-e49f-4586-a36e-6fad52908b6f)

## SSH Connection

The console can be accessed over the Thinger.io web console, but there is also a possibility for connecting devices over standard SSH connections from the Internet (no local network required). This feature is a work in progress and will be released soon as a plugin!

![](https://2241973068-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LpXqB3J1BMD5s4OpYSg%2F-MkcCAlmMnCcar5Butlq%2F-MkcCmA05ZZhlfzhZSP3%2FEb2X26QTRh.gif?alt=media\&token=fb2ee922-a069-4f6c-a574-07eff14c7cf9)
