Skip to content

Instantly share code, notes, and snippets.

@alex-tomin
Last active January 16, 2024 12:40
Show Gist options
  • Save alex-tomin/fafb36269719ef944bb093f7fa2d3a99 to your computer and use it in GitHub Desktop.
Save alex-tomin/fafb36269719ef944bb093f7fa2d3a99 to your computer and use it in GitHub Desktop.
ESP Home - Connect to MQTT with x509 Client Certificate. (Azure Event Grid)

ESPHome: Connecting to Secure MQTT Server from esp 8266 / esp32

In this example I tried to Connect to Azure Event Grid. Which worked in MQTTX (you can download the tool here), but ESP Home does not support it out of the box. See esphome/feature-requests#1019

This example receives a json message in the following format and converts values to few sensors.

{
  "IncidentId": "1234456",
  "Team":"HardWorkers",
  "Title":"Power Loss",
  "Severity":"2",
  "Type":"Outage",
  "Role":""
}

To use the Below Example:

  1. Make sure you have it working in MQTTX. It is easier to troubleshoot via a desktop tool, rather than in ESP device.
  2. Supply the values in the MqttGrid.h file:
    • Client Id - to ensure value not repeating
    • Mqtt Host, like <evnt-grid>.westus2-1.ts.eventgrid.azure.net for Azure Event Grid
    • Port is usually 8883, so it is hardcoded below
    • Username - the one configured in evengrid and validated in mqtt.
    • topic to subscribe to
    • Certificate exported in PEM format (If created in Key Vault, it contains both public certificate and private Key)
  3. You can use the above json example to send to mqtt (make sure you specify proper topic, the one you subscribed to)
  4. Update Yaml file to specify you passwords and wifi connection details

Creadits and Links

#pragma once
#include "esphome.h"
#include <PubSubClient.h>
#include <WiFiClientSecure.h>
#include <ArduinoJson.h>
#define TAG "MqttGrid"
class MqttGrid : public Component {
public:
TextSensor *incident_id_sensor = new TextSensor();
TextSensor *incident_team_sensor = new TextSensor();
TextSensor *incident_title_sensor = new TextSensor();
TextSensor *incident_role_sensor = new TextSensor();
TextSensor *incident_severity_sensor = new TextSensor();
long lastReconnectAttempt = 0;
//TODO: put your values
const char *mqtt_server = "<event_grid_name>.westus2-1.ts.eventgrid.azure.net";
const char *user_name = "<user_name>";
const char *client_id = "sample-device-esp";
const char *topic ="kiosk-incidents/#";
//note: mind indentation, should be no spaces in the beginning of the line.
const char *certPem = R"(
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDc4Kveii5JY+lm
....
RW74ULxFmhIG2aEmmZt3tq45
-----END PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIIDTDCCAjSgAwIBAgIQfdEnhcKaRGqVc1s6mh0B2TANBgkqhkiG9w0BAQsFADAj
...
anWy6O29fetchPlKyT5EmpylYpfYFhYnUCRqe2ey63Z3zsFKtdr0D/8EU40Uc2Ar
soGMhcN7+aNSE9MD/VjPTeWylxmvMFlsWhHuF45V2BY=
-----END CERTIFICATE-----
)";
WiFiClientSecure wifiClient;
PubSubClient client;
MqttGrid() : client(mqtt_server, 8883, wifiClient){
client.setCallback([this](char* topic, byte* message, unsigned int length) { this->on_icm(topic, message, length); });
}
float get_setup_priority() const override { return esphome::setup_priority::AFTER_CONNECTION; }
void on_icm(char* topic, byte* message, unsigned int length) {
ESP_LOGD(TAG, "Message arrived on topic: '%s'", topic);
DynamicJsonDocument json_buffer(1024);
DeserializationError error = deserializeJson(json_buffer, message);
if (error) {
ESP_LOGE(TAG, "Json deserialization failed: '%s'", error.f_str());
return;
}
incident_id_sensor->publish_state(json_buffer["IncidentId"]);
incident_team_sensor->publish_state(json_buffer["Team"]);
incident_title_sensor->publish_state(json_buffer["Title"]);
incident_role_sensor->publish_state(json_buffer["Role"]);
incident_severity_sensor->publish_state(json_buffer["Severity"]);
}
// Load Certificates
void loadcerts() {
#if defined(ESP32)
// note cannot use insecure mode in ESP32 - client certs won't be sent. Perhaps a bug in wifiClientSecure.
wifiClient.setCACert(ca_pem);
wifiClient.setCertificate(certPem);
wifiClient.setPrivateKey(keyPem);
#elif defined(ESP8266)
wifiClient.allowSelfSignedCerts();
wifiClient.setInsecure();
BearSSL::X509List certList(certPem);
BearSSL::PrivateKey privateKey(certPem);
wifiClient.setClientRSACert(&certList, &privateKey);
#else
#error "This ain't a ESP8266 or ESP32 cannot support it!"
#endif
ESP_LOGD(TAG, "Checking TLS connection to '%s'", mqtt_server);
if (!wifiClient.connect(mqtt_server, 8883)) {
ESP_LOGE(TAG,"connection failed");
return;
}
ESP_LOGD(TAG, "Connection OK");
}
boolean reconnect()
{
if (client.connected()) return true;
long now = millis();
if (now - lastReconnectAttempt < 2000) return false;
lastReconnectAttempt = now;
ESP_LOGD(TAG, "trying to connect to MQTT");
if (client.connect(client_id, user_name, ""))
{
client.subscribe(topic);
ESP_LOGI(TAG, "===> mqtt connected");
}
else
{
ESP_LOGE(TAG, "---> mqtt failed, rc='%d'", client.state());
}
return client.connected();
}
void setup() override
{
loadcerts();
}
void loop() override
{
if (!client.connected())
{
reconnect();
}
client.loop();
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment