Post

IOT - ESP32 Remotely

IOT - ESP32 Remotely

Can we simply SSH to the ESP32 for remote config or some sort?
Of course it does not natively support SSH in the same way as full-fledged Linux devices, but it can be configured to mimic similar functionality using various techniques. Here’s an overview of the possibilities:


Native SSH Support

  • Not Available: The ESP32 lacks an operating system like Linux to natively support SSH (Secure Shell). SSH requires software like OpenSSH or Dropbear, which the ESP32 cannot run due to limited resources.

Alternative Options for Remote Configuration

1. Using Telnet or Custom TCP Server

  • Telnet: You can use libraries like TelnetStream or write a custom Telnet-like server for remote text-based communication.
    • Libraries: The TelnetStream library simplifies Telnet server implementation for the ESP32.
    • Security: Telnet lacks encryption; use it in isolated or development environments only.
  • Custom TCP Server: You can write a TCP server on the ESP32 to accept commands and configure parameters remotely.

Example: Simple Telnet Implementation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <WiFi.h>
#include <TelnetStream.h>

const char* ssid = "YOUR_WIFI_SSID";
const char* password = "YOUR_WIFI_PASSWORD";

void setup() {
  Serial.begin(115200);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("WiFi connected!");

  TelnetStream.begin();
}

void loop() {
  if (TelnetStream.available()) {
    String command = TelnetStream.readStringUntil('\n');
    TelnetStream.println("Received command: " + command);
    // Handle commands
  }
}

2. Web-Based Configuration

  • Web Server: Run a lightweight web server on the ESP32, allowing configuration changes via a browser.
    • Libraries like ESPAsyncWebServer make it easy to create user-friendly interfaces.
    • Security: Implement HTTPS (with TLS) for secure communication.

Example: Basic Web Server for Configuration

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <WiFi.h>
#include <WebServer.h>

const char* ssid = "YOUR_WIFI_SSID";
const char* password = "YOUR_WIFI_PASSWORD";

WebServer server(80);

void handleRoot() {
  server.send(200, "text/plain", "ESP32 Web Config Page");
}

void setup() {
  Serial.begin(115200);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("WiFi connected!");

  server.on("/", handleRoot);
  server.begin();
}

void loop() {
  server.handleClient();
}

3. MQTT for Remote Configuration

  • Use MQTT to send and receive configuration commands.
  • Example: Publish configuration changes (e.g., WiFi SSID, passwords, or operational parameters) to specific topics.

4. Over-the-Air (OTA) Updates

  • OTA allows updating firmware and configurations remotely.
  • Use the ArduinoOTA library to upload new code or configurations wirelessly.

5. Secure Shell-Like Functionality with ESP-IDF

  • The ESP-IDF framework (official SDK for ESP32) allows advanced features.
  • You can implement a custom shell-like interface using the ESP-IDF console or FreeRTOS tasks.
  • Example: Use UART, Telnet, or a WebSocket for interactive sessions.

Best Practices for Secure Remote Configuration

  1. Encryption: Use SSL/TLS (via the mbedtls library) for secure communication.
  2. Authentication: Require user credentials for any configuration interface.
  3. Restricted Access: Limit access to trusted devices or IP ranges.
  4. Audit Logs: Maintain logs of configuration changes if possible.
  5. Firmware Updates: Enable OTA for easy patching of vulnerabilities.

While the ESP32 does not natively support SSH, these alternatives can provide secure and flexible methods to remotely configure the device.

To achieve a secure and configurable setup for two ESP32 Devkit-C devices with DHT22 sensors communicating with a Mosquitto server, the devices will:

  1. Publish sensor data to the Mosquitto server.
  2. Subscribe to a configuration topic for remote reconfiguration.
  3. Use TLS for secure communication with the Mosquitto broker.

Wiring Example for Each Device

DHT22 Pinout:

  • VCC (Pin 1): Connect to 3.3V on ESP32.
  • Data (Pin 2): Connect to GPIO4 on ESP32 (can be adjusted in code).
  • GND (Pin 4): Connect to GND on ESP32.

Steps to Set Up Secure Communication

  1. Generate SSL/TLS Certificates for Mosquitto Server
    Follow the steps here to generate server certificates. Ensure the certificates are in place and the Mosquitto broker is configured to use them.

  2. Prepare ESP32 with Certificates Convert the Mosquitto server’s CA certificate (ca.crt) to a format compatible with the ESP32 and include it in the Arduino IDE.

  3. Install Required Arduino Libraries

    • PubSubClient for MQTT
    • Adafruit Unified Sensor and DHT Sensor Library

Code for Each ESP32 Device

Common Configuration

  1. ESP32 Device 1 Script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#include <WiFi.h>
#include <PubSubClient.h>
#include <DHT.h>
#include <WiFiClientSecure.h>

// DHT22 Configuration
#define DHTPIN 4
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);

// WiFi and MQTT Configuration
const char* ssid = "YOUR_WIFI_SSID";
const char* password = "YOUR_WIFI_PASSWORD";
const char* mqtt_server = "YOUR_MQTT_BROKER_IP";
const int mqtt_port = 8883; // Secure MQTT port

const char* device_id = "device1";
const char* data_topic = "devices/device1/data";
const char* config_topic = "devices/device1/config";

// Root CA certificate
const char* ca_cert = \
"-----BEGIN CERTIFICATE-----\n" \
"YOUR_CA_CERTIFICATE_HERE\n" \
"-----END CERTIFICATE-----\n";

WiFiClientSecure secureClient;
PubSubClient client(secureClient);

String mqtt_username = "YOUR_MQTT_USERNAME";
String mqtt_password = "YOUR_MQTT_PASSWORD";

void connectWiFi() {
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("WiFi connected");
}

void reconnectMQTT() {
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    if (client.connect(device_id, mqtt_username.c_str(), mqtt_password.c_str())) {
      Serial.println("Connected to MQTT");
      client.subscribe(config_topic);
    } else {
      Serial.print("Failed, rc=");
      Serial.print(client.state());
      Serial.println(" Trying again in 5 seconds");
      delay(5000);
    }
  }
}

void callback(char* topic, byte* message, unsigned int length) {
  String incomingMessage;
  for (unsigned int i = 0; i < length; i++) {
    incomingMessage += (char)message[i];
  }
  Serial.println("Message received: " + incomingMessage);

  // Parse configuration commands
  if (String(topic) == config_topic) {
    if (incomingMessage.startsWith("update_wifi")) {
      // Parse new SSID and password
      int ssidIndex = incomingMessage.indexOf(" ") + 1;
      int passwordIndex = incomingMessage.lastIndexOf(" ") + 1;
      String newSSID = incomingMessage.substring(ssidIndex, passwordIndex - 1);
      String newPassword = incomingMessage.substring(passwordIndex);

      // Update WiFi configuration
      WiFi.begin(newSSID.c_str(), newPassword.c_str());
      Serial.println("Updating WiFi configuration...");
    }
  }
}

void setup() {
  Serial.begin(115200);
  dht.begin();

  connectWiFi();

  secureClient.setCACert(ca_cert);
  client.setServer(mqtt_server, mqtt_port);
  client.setCallback(callback);
}

void loop() {
  if (!client.connected()) {
    reconnectMQTT();
  }
  client.loop();

  // Read sensor data
  float temperature = dht.readTemperature();
  float humidity = dht.readHumidity();
  if (isnan(temperature) || isnan(humidity)) {
    Serial.println("Failed to read from DHT sensor!");
    return;
  }

  // Prepare JSON payload
  String payload = "{\"temperature\": " + String(temperature) + ", \"humidity\": " + String(humidity) + "}";
  client.publish(data_topic, payload.c_str());
  Serial.println("Published data: " + payload);

  delay(5000);
}
  1. ESP32 Device 2 Script
    Change only the device_id, data_topic, and config_topic values to device2 and devices/device2/....

Secure Mosquitto Configuration

  1. Enable TLS in the Mosquitto configuration file (/etc/mosquitto/mosquitto.conf):
    1
    2
    3
    4
    5
    6
    7
    
    listener 8883
    cafile /path/to/ca.crt
    certfile /path/to/server.crt
    keyfile /path/to/server.key
    
    allow_anonymous false
    password_file /etc/mosquitto/passwordfile
    
  2. Create MQTT username and password:
    1
    2
    
    mosquitto_passwd -c /etc/mosquitto/passwordfile YOUR_MQTT_USERNAME
    systemctl restart mosquitto
    

Testing

  1. Verify Mosquitto broker is running with TLS enabled.
  2. Use tools like MQTT Explorer to verify data is being published securely.
  3. Publish commands to devices/device1/config to test configuration updates.

Configurations Supported by the Provided Code

The code supports reconfiguration of the following parameters dynamically via MQTT messages:

  1. Wi-Fi Credentials
    Allows the ESP32 to switch to a new Wi-Fi network without requiring reprogramming.

    • Command format:
      1
      
      update_wifi NEW_SSID NEW_PASSWORD
      

    Example:

    1
    
    update_wifi MyNewSSID MyNewPassword
    
  2. Additional Parameters (extendable in code)
    The code can be extended to include more reconfigurable parameters. Examples include:

    • MQTT topics for publishing/subscribing.
    • Publish interval for sensor data.
    • Thresholds for specific alerts (e.g., high temperature or humidity).

Sending Configuration Commands from the MQTT Server

To send configuration commands, you can use an MQTT client like MQTT Explorer, mosquitto_pub, or a Python script.

Using mosquitto_pub Command

Example command to update Wi-Fi credentials:

1
mosquitto_pub -h YOUR_MQTT_BROKER_IP -p 8883 --cafile /path/to/ca.crt -u "YOUR_MQTT_USERNAME" -P "YOUR_MQTT_PASSWORD" -t "devices/device1/config" -m "update_wifi MyNewSSID MyNewPassword"

Explanation:

  • -h: MQTT broker address
  • -p: Port number (secure port: 8883)
  • --cafile: Path to the CA certificate for secure communication
  • -u: MQTT username
  • -P: MQTT password
  • -t: MQTT topic (devices/device1/config)
  • -m: Message payload (update_wifi MyNewSSID MyNewPassword)

Using MQTT Explorer

  1. Connect to your MQTT broker with TLS enabled.
  2. Navigate to the configuration topic for the device (e.g., devices/device1/config).
  3. Publish a message in the correct format:
    1
    
    update_wifi MyNewSSID MyNewPassword
    

Extending the Code for Additional Configurations

You can add more configuration commands by extending the callback function in the code. For example:

1
2
3
4
5
if (incomingMessage.startsWith("set_publish_interval")) {
  int newInterval = incomingMessage.substring(incomingMessage.indexOf(" ") + 1).toInt();
  publishInterval = newInterval;
  Serial.println("Updated publish interval to: " + String(publishInterval));
}

To send the updated publish interval:

1
mosquitto_pub -h YOUR_MQTT_BROKER_IP -p 8883 --cafile /path/to/ca.crt -u "YOUR_MQTT_USERNAME" -P "YOUR_MQTT_PASSWORD" -t "devices/device1/config" -m "set_publish_interval 10000"

Here:

  • set_publish_interval 10000 updates the publish interval to 10 seconds (10000 milliseconds).

Validation

  1. Monitor the device logs via the Arduino Serial Monitor to see the effect of the commands.
  2. Ensure commands are applied correctly and persist after the MQTT client reconnects to the server.
This post is licensed under CC BY 4.0 by the author.