Sitemap
T Asato

T Asato

Send BLE command triggered by MQTT publish message from Remote Broker

4 min readSep 25, 2025

--

Background

In the previous post, I confirmed that a smart phone app can connect MQTT broker on a VPS server and can publish & subscribe MQTT messages.

In this post, I connect the broker from Raspberry Pi and send some BLE commad.

I updated my IoT device hub application so that it can receive MQTT publish message and send BLE command to a IoT device.

libmosquitto settings

Send CA certificate, client certificate and client key created in the previous post to RaspberryPi.
Any location would work if IotDeviceHub can access the directory, since certificats path can be set by mosquitto_tls_set().

Remote broker address and port also need to be configured. To aggregate configuration setting, created aJSON file so that IotDeviceHub can get all necessary configuration parameters.

// IotDeviceHub/config/config.json
{
"mqtt":
{
"brokerIpv4": <address>,
"brokerPort": <port>,
"caCert": <caCertPath>,
"clientCert": <clientCertPath>,
"clientKey": <keyPath>
}
}

Using POCO to parse JSON file.
The JSON is read at MQTT manager class constructor.

MqttManager::MqttManager()
{
try
{
Poco::Util::JSONConfiguration config = Poco::Util::JSONConfiguration(CONFIG_FILE_PATH);
mBrokerIpv4 = config.getString("mqtt.brokerIpv4");
std::cout << "MQTT broker address: " << mBrokerIpv4 << std::endl;
mBrokerPort = config.getUInt16("mqtt.brokerPort");
std::cout << "MQTT broker port: " << mBrokerPort << std::endl;
mCaCertPath = config.getString("mqtt.caCert");
std::cout << "MQTT CA cert path: " << mCaCertPath << std::endl;
mClientCertPath = config.getString("mqtt.clientCert");
std::cout << "MQTT client cert path: " << mClientCertPath << std::endl;
mClientKeyPath = config.getString("mqtt.clientKey");
std::cout << "MQTT client key path: "<< mClientKeyPath << std::endl;
}
catch (Poco::Exception& ex)
{
std::cerr << "Error: " << ex.displayText() << std::endl;
}
}

Setting certificates and broker address, etc. by mosquitto_tls_set() and mosquitto_connect_bind_v5().

//IotDeviceHub/mqtt/MqttManager.cpp
auto ret = mosquitto_tls_set(m_mosq, mCaCertPath.c_str(), NULL, mClientCertPath.c_str(), mClientKeyPath.c_str(), NULL);
:
ret = mosquitto_connect_bind_v5(m_mosq, mBrokerIpv4.c_str(), mBrokerPort, 60, nullptr, nullptr);

Setting callback messages for MQTT messages

When IotDeviceHub receives MQTT Publish messages, it should send respective BLE commands to device from a callback function registered before.

Get T Asato’s stories in your inbox

Join Medium for free to get updates from this writer.

In libmosquitto, you can set callback function via mosquitto_message_v5_callback_set(). However, libmosquitto is C library and cannot bind a member function and its class instance.
As a workaround, pass this pointer when it create mosquitto client instance. By doing so, this will be assinged in obj argument of the callback functin, so it can access public member function of the class.

//bool MqttManager::init(std::string client_id)
m_mosq = mosquitto_new(client_id.c_str(), true, this);
void on_message(struct mosquitto *mosq, void *obj, const struct mosquitto_message *msg, const mosquitto_property *props)
{
auto *manager = static_cast<MqttManager*>(obj);
if(manager)
{
manager->onMessageReceived(msg);
}

}

Side info, IotDeviceHub is using Mediator pattern for event handling (see below post).
So in this case, using MQTT topic name as a event name and payload as a event data.

void MqttManager::onMessageReceived(const struct mosquitto_message *msg)
{
if(mMediator)
{
std::string eventData="";
if(msg->payload == nullptr || msg->payloadlen == 0)
{
std::cerr << "Received empty message on topic " << msg->topic << std::endl;
}
else
{
eventData=std::string((char *)msg->payload, msg->payloadlen);
}
mMediator->onEvent(msg->topic, eventData);
}
else
{
std::cerr << "Mediator not set, cannot handle message on topic " << msg->topic << std::endl;
}
}

In a client of MQTT manager (who send BLE command to devices), it subscribe “exec_bot”, and register it as a Mediator”s event.
When this topic is received, a lambda expression is executed to send a command to the BLE device (mBotDevice).

//bool IotDeviceHubManager::init()
mMqtt->subscribe("exec_bot");
mEventManager->registerEventHandler("exec_bot", [this](const std::string& eventData)
{
std::cout << "Event: exec_bot" << std::endl;
auto command = mBotDevice->getExecActionCommand();
mBle->sendBleCommand(command);
}
);
mMqtt->setMediator(mEventManager);

Experiment

As an experiment, I checked whether the Switchbot Bot execution could be performed via MQTT.

First, attach the Switchbot Bot to my AC controller.
If you don’t attach it properly, the Bot will move when it’s turned on and you won’t be able to press the buttons, so attach it firmly with masking tape.
This has a fatal flaw in that you won’t be able to see the screen on the controller, but I ignore that for now.

Press enter or click to view image in full size

After that, set up a button panel to publish the “exec_bot” topic in the smartphone app introduced in the first article, and press the button.

Result

When I published the “exec_bot” topic from the smartphone app, the bot worked.
Of course, this still doesn’t allow for normal use, so more mechanical improvements are needed, but now that I can control indoor devices via the Internet, I think it’s starting to feel more like IoT.

--

--