php-mqtt / laravel-client Goto Github PK
View Code? Open in Web Editor NEWAn MQTT client library for Laravel.
License: MIT License
An MQTT client library for Laravel.
License: MIT License
Hi, Thanks for the package! I was wondering, can we do multiple subscribe in 1 cli artisan command?
My Command :
php artisan mqtt-subscribe
Code handler :
foreach (Device::all() as $device) {
$mqtt->subscribe($device->subscribe_topic, function( ... ) { ... }, 1);
$mqtt->loop(true);
}
I'm planning to run this command on supervisor with autorestart on. Is this good approach? Thanks!
I can see @Namoshek's already done some work to support Laravel 10 and PHP 8.2, so just wanted to add an issue to track this.
I've got a new-ish project that uses this package and Laravel 9 that I'm keen to upgrade to Laravel 10. Let me know if there's anything I can do to help!
Hi there,
Calling a Job inside the subscribe callback seems to segfault as the call just ends with nothing in the logs other than exceptions within docker.
In this instance the setup and loop are in an artisan command.
$mqtt = MQTT::connection();
$mqtt->subscribe('test/+', function (string $topic, string $message) {
$this->info("Received message on topic {$topic}");
HandleMqttMessage::dispatch($topic, $message);
$this->info("Complete");
}, 1);
In this instance, the "Complete" message is never reached.
Laravel 10
PHP 8.2
Tried both redis
and sync
QUEUE_CONNECTION
Any suggestions would be much appreciated :)
I'm getting the following exception when running below code:
PhpMqtt \ Client \ Exceptions \ ClientNotConnectedToBrokerException (192)
[192] Transferring data over socket failed: The client is not connected to a broker. The requested operation is impossible at this point.
My code:
public function subDeviceAll(Request $request)
{
$device = Device::all();
$dataDevice = [];
foreach ($device as $key => $value) {
$data['data_device'] = $value;
$data['status'] = $this->checkDeviceOnline($value['device_id']);
$data['power'] = $this->checkDevicePower($value['device_id']);
$dataDevice[] = $data;
}
return response()->json($dataDevice, 200);
}
public function checkDeviceOnline($device_id)
{
$device = Device::where('device_id', $device_id)->first();
$mqtt = MQTT::connection();
$res = '';
$topic = $device['topic'];
$mqtt->publish('cmnd/' . $topic . '/POWER', '', 0);
$mqtt->subscribe('tele/' . $topic . '/LWT', function (string $topic, string $message) use ($mqtt, &$res) {
$res = $message;
$mqtt->interrupt();
}, 0);
$mqtt->loop(true);
$mqtt->disconnect();
return $res;
}
public function checkDevicePower($device_id)
{
$device = Device::where('device_id', $device_id)->first();
$mqtt = MQTT::connection();
$res = '';
$topic = $device['topic'];
$mqtt->publish('cmnd/' . $topic . '/POWER', '', 0);
$mqtt->subscribe('stat/' . $topic . '/POWER', function (string $topic, string $message) use ($mqtt, &$res) {
$res = $message;
$mqtt->interrupt();
}, 0);
$mqtt->loop(true);
$mqtt->disconnect();
return $res;
}
can we publish topic on two different port: Tcp Port: 1883, Websocket Port: 8000
this is what the message returns after using composer require php-mqtt/laravel-client :
Problem 1
- php-mqtt/client[v1.1.0, ..., v1.1.1] require psr/log ^1.1 -> found psr/log[1.1.0, ..., 1.1.4] but the package is fixed to 2.0.0 (lock file version) by a partial update and that version does not match. Make sure you list it as an argument for the update command.
- Root composer.json requires php-mqtt/client ^1.1 -> satisfiable by php-mqtt/client[v1.1.0, v1.1.1].
First, thank you for building this package, it really helps me in my laravel development.
I use this library to subscribe and receive payloads from my MQTT broker that publish new payload every 0.4 seconds in the command console. My question is, "Is there a way to detect if the response is not receive from the MQTT broker for a specified duration?"
I tried using timeout for the last response received and put it in the resgisterLoopEventHandler function but it does not work. Here is my current code:
try{
$mqtt = MQTT::connection();
$mqtt->subscribe($topic, function (string $topic, string $message) use (&$lastPayloadTime, $mqtt){
$lastPayloadTime = Carbon::now();
echo $lastPayloadTime . "\n";
echo sprintf('Received QoS level 1 message on topic [%s]: %s', $topic, $message) . "\n";
$mqtt->interrupt();
}, 0);
$mqtt->registerLoopEventHandler(function (MqttClient $client, float $elapsedTime) use (&$lastPayloadTime, $mqtt, $timeout) {
if ($lastPayloadTime->diffInSeconds(Carbon::now()) > $timeout) {
echo "Payload not received within $timeoutDuration seconds.\n";
$client->interrupt();
}
});
$mqtt->loop();
$mqtt->disconnect();
}catch (MqttClientException $e) {
echo $e;
}
I really appreciate your help on this. Thank you
Hi,
When create a subscribe in my controller, I get data from json, this is perfect but if I send data Raw o Hex, the result es null why?
This is my controller.
public function subscribe()
{
$topic = 'kitcken/rpi';
$result = [];
$mqtt = MQTT::connection();
$mqtt->subscribe($topic, function (string $topic, string $message) use ($mqtt, &$result) {
$result['topic'] = $topic;
$result['message'] = json_decode($message);
$mqtt->interrupt();
}, 0);
$mqtt->loop(true);
$data = json_encode($result);
Storage::disk('local')->put('result_mqtt.txt',$data);
return response()->json($result, 200);
}
$mqtt = MQTT::connection();
$mqtt->subscribe('stat/xxxxxxxx/POWER', function (string $topic, string $message) {
return response()->json(['topic' => $topic, 'message' => $message], 200);
}, 0);
return empty
But on MQTT Dashboard (App android) this topic working
And publish working
Hello,
I hope this message finds you well. I am currently using your php-mqtt/laravel-client library in one of my projects and I find it extremely useful. However, I have noticed that the MQTT facade and ConnectionManager class could benefit from the addition of interrupt and subscribe methods.
The interrupt method would be useful to exit the loop during the next iteration, which can be particularly handy in certain use cases. The subscribe method, on the other hand, would allow subscribing to topics, which is a common requirement in MQTT applications.
Here is a idea of what the methods could look like with addition the README update:
namespace PhpMqtt\Client\Facades;
use Illuminate\Support\Facades\Facade;
use PhpMqtt\Client\ConnectionManager;
use PhpMqtt\Client\Contracts\MqttClient;
/**
* @method static MqttClient connection(string $name = null)
* @method static void interrupt(string $connection = null) // add interrupt to MQTT Facade
* @method static void disconnect(string $connection = null)
* @method static void publish(string $topic, string $message, bool $retain = false, string $connection = null)
* @method static void subscribe(string $topic, callable $message, int $qos = 0, string $connection = null) // add subscribe to MQTT Facade
// ...
/**
* Interrupts the given connection if opened.
*
* @param string|null $connection
*/
public function interrupt(string $connection = null): void
{
if ($connection === null) {
$connection = $this->defaultConnection;
}
if (array_key_exists($connection, $this->connections)) {
$this->connections[$connection]->interrupt();
}
}
/**
* Subscribes to the given topic on the given connection.
*
* @param string $topic
* @param callable $message
* @param int $qos
* @param string|null $connection
* @throws BindingResolutionException
* @throws ConfigurationInvalidException
* @throws ConnectingToBrokerFailedException
* @throws ConnectionNotAvailableException
* @throws DataTransferException
* @throws ProtocolNotSupportedException
* @throws RepositoryException
*/
public function subscribe(string $topic, callable $message, int $qos = 0, string $connection = null): void
{
$client = $this->connection($connection);
$client->subscribe($topic, $message, $qos);
}
// ...
In order to escape the loop, you can also call MQTT::interrupt()
which will exit the loop during
the next iteration. The method can, for example, be called in a registered signal handler:
/** @var \PhpMqtt\Client\Contracts\MqttClient $mqtt */
pcntl_signal(SIGINT, function () use ($mqtt) {
MQTT::interrupt();
});
Very similar to publishing with QoS level 1 and 2, subscribing requires to run an event loop.
Although before running the loop, topics need to be subscribed to:
use PhpMqtt\Client\Facades\MQTT;
MQTT::subscribe('some/topic', function (string $topic, string $message) {
echo sprintf('Received QoS level 1 message on topic [%s]: %s', $topic, $message);
}, 1);
MQTT::connection()->loop(true);
If you agree with these changes, I would be more than happy to contribute and push my changes via a pull request. Please let me know if you would like me to proceed with this.
Best regards, StevenFV
its return follow :
Problem 1
- php-mqtt/laravel-client[v1.0.0-rc1, ..., v1.0.0] require illuminate/config ~7.0|~8.0 -> found illuminate/config[v7.0.0, ..., 7.x-dev, v8.0.0, ..., 8.x-dev] but these were not loaded, likely because it conflicts with another require.
- Root composer.json requires php-mqtt/laravel-client ^1.0 -> satisfiable by php-mqtt/laravel-client[v1.0.0-rc1, v1.0.0-rc2, v1.0.0].
Is there a way to make this work..
I'm trying to publish a 'PING' request to a device, and then subscribe to another channel and wait for the 'PONG' response. Here's the code:
public function ping(Request $request)
{
$device = Device::find($request->id);
if ($device) {
//Listen on laravel_device_DEVICEID
$listen_topic = 'laravel_device_' . $device->device_id;
$result = [];
$mqtt = MQTT::connection();
$mqtt->subscribe($listen_topic, function (string $topic, string $message) use ($mqtt, &$result) {
$result['topic'] = $topic;
$result['message'] = $message;
$mqtt->interrupt();
}, 0);
$mqtt->loop(true, true);
//Submit PING message
$topic = $device->device_id;
$message = json_encode([
'type' => 'ping',
'device_id' => $device->device_id
]);
$mqtt = MQTT::connection();
$mqtt->publish($topic, $message);
$device->last_ping_response = 2;
$device->save();
}
}
Sometimes find this error
PhpMqtt \ Client \ Exceptions \ DataTransferException (66)
[66] Transferring data over socket failed: Reading data from the socket failed. Has it been closed?
https://github.com/php-mqtt/client recently released v2.0
Hi, I'm trying to do subscribe where I call Device
model inside my console command.
public function handle()
{
$mqtt = MQTT::connection();
foreach (Device::all() as $device) {
$mqtt->subscribe($device->subscribe_topic, function (string $topic, string $message) use ($device) {
echo "Received message on topic: {$topic}\n";
echo "Received message with payload: {$message}\n";
}, 0);
}
$mqtt->loop(true);
}
But I want it to dynamically change when New Device is added inside the controllers. What's the best approach to make it happen?
Hi, First, i want to say thank you for making this package. it helps me so much as a laravel dev.
my question is, "is it possible to make the laravel can be accessed while doing a loop?"
what i was trying to do is, keep subscribing the mqtt, post each of the subs to database, and accessing another page at the same time (i was planning to create a log dashboard in another page for a user).
but when im doing a loop, the laravel keep load the loop and make the other page (which is the log dashboard) can't be accessed. it does a infinite load.
my controller is :
public function mqtt()
{
$mqtt = MQTT::connection();
// Register a hook which is called once per loop and which interrupts the loop after some time.
// $mqtt->registerLoopEventHandler(function (MqttClient $mqtt, float $elapsedTime) {
// if ($elapsedTime >= 40) {
// $mqtt->interrupt();
// }
// });
// subscribe
$mqtt->subscribe('#', function (string $topic, string $message) use ($mqtt, &$result) {
$json = json_decode($message, true);
ModelOne::insert($json);
}, 0);
$mqtt->loop(true);
}
is it possible? thank you
Project on localhost works fine but the hosted version is not working
Referrer Policy: strict-origin-when-cross-origin with http and https request
Which Version of Laravel does it support?
how can i change web socket port
this is public server i use it work
Broker: broker.hivemq.com
TCP Port: 1883
Websocket Port: 8000
now i need to change it to private but it have another websocket port its 8884 how can i change this from code
Please update settings to enable suppot for option useBlockingSocket.
I try to connect my Laravel web application to a MQTT broker with SSL/TLS. I have configure the .env file in my web application:
MQTT_HOST=//mosquitto
MQTT_PORT=8883
MQTT_TLS_ENABLED=true
MQTT_TLS_ALLOW_SELF_SIGNED_CERT=true
MQTT_TLS_CA_FILE=/usr/local/share/ca-certificates/ca.crt
MQTT_TLS_CLIENT_CERT_FILE=/usr/local/share/ca-certificates/client.crt
MQTT_TLS_CLIENT_CERT_KEY_FILE=/usr/local/share/ca-certificates/client.key
It seems to have an issue because I get this error when the app try to connect:
PhpMqtt\Client\Exceptions\ConfigurationInvalidException
Certificate Authority file setting must contain the path to a regular file.
I have try to add quotes, double quotes and curly brakets but nothing works.
I have triple check the pathname and all is good.
When I dump and die the env variable I get the good path:
It have something I doing wrong or is an issue with the package?
How can I publish a message as a bytes array in a specific topic?
Hello, first thanks for the library and work.
Now, I have a question: Can we use this library to make a MQTT sink to store ALL the MQTT messages(which are going to be a lot!) onto the database (like with the usual, eloquent new() and model->save(); helpers when storing information)?
Like this example: https://github.com/php-mqtt/client-examples/blob/master/04_hooks/03_use_a_message_received_event_handler_to_log_received_messages.php but storing on the database.
Or its just too much for PHP and better do it with othe technologies like kafka or some script in NodeJS/Python.
I am trying to connnect with hivemq broker but getting this connection error.
Hi,
Thanks for this greats libraries. I was hoping to use as broadcast driver in laravel, it's possible?
Thx
PhpMqtt\Client\Exceptions\ConnectingToBrokerFailedException
[1000] Establishing a connection to the MQTT broker failed: Socket error [101]: Network is unreachable
When I am trying to connect to AWS IoT core through Godaddy Server(Shared Hosting) above error is showing but when i am connecting through locally it's working fine.
Please help in this. Thanks in advance
Hi. How can i unsubscribe from channel?
$mqtt = MQTT::connection(); $mqtt->unsubscribe('mergen/2/sync'); $mqtt->disconnect();
this code not working. I'm using laravel 10.
Hey,
We want to store the certificate files on a different disk (S3) because we are suing Vapor which doesnt have local storage.
I wasnt able to find a way to do this.
Did I miss a way to handle this ?
Thanks!
This is a huge tip for the users of this library. It can safe some frustrated hours.
I have an API. When an endpoint is called, it starts a job on the queue. In this job, a MQTT message is published. The code below is the code that runs in the job.
$topic = sprintf("Vennens/MVA/%d/Silo/%d/Alternatieven", $this->plc, $this->silo);
$mqtt = MQTT::connection();
$mqtt->publish($topic, json_encode([
'alternatief_1' => $this->alternatief_1,
'alternatief_2' => $this->alternatief_2,
'alternatief_3' => $this->alternatief_3,
'alternatief_4' => $this->alternatief_4,
]), 2);
$mqtt->loop(true, true, 5);
$mqtt->disconnect();
The first job process goes great. But when I do a second request. The job failes. You get an exception that there is no connection.
The problem is that the Laravel queue worker keeps it's app state. In the MQTT class, it stores the connections in an array. When you call $mqtt->disconnect(). The connection is closed, but remains in the connections array.
When trying to reopen the connection on the second process, it fails. The socket is not open.
You have to call MQTT::disconnect(). This closes the socket and removes connection from the array.
$topic = sprintf("Vennens/MVA/%d/Silo/%d/Alternatieven", $this->plc, $this->silo);
$mqtt = MQTT::connection();
$mqtt->publish($topic, json_encode([
'alternatief_1' => $this->alternatief_1,
'alternatief_2' => $this->alternatief_2,
'alternatief_3' => $this->alternatief_3,
'alternatief_4' => $this->alternatief_4,
]), 2);
$mqtt->loop(true, true, 5);
MQTT::disconnect();
Hi, I have a controller in where I need to send a message over the socket, wait for an acknowledge and if the ack doesn't arrive in 10 or so seconds it interrupts the connection and prints something.
I tried this way:
$mqtt = MQTT::connection();
$mqtt->subscribe('/device/'.$serial, function ($topic, $message) use ($mqtt, $rele, $device, $CID) {
$message = json_decode($message);
if ($message->msg == 'ACK' && $message->CID == $CID){
Log::info('ACK Received');
if($device->getReleStatus($rele)==0) $device->setReleStatus($rele,1);
else $device->setReleStatus($rele,0);
$device->save();
}
$mqtt->interrupt();
});
$mqtt->publish('/device/'.$serial, json_encode($msg));
$mqtt->loop(true);
$mqtt->disconnect();
I found the socket timeout options inside the configuration file, but I'm not sure it is what i'm looking for as the connection stays open (and the request to the controller hangs forever).
Is this possible or do I have to find a workaround?
I got this error when trying to send data over 1MB [65] Transferring data over socket failed: Sending data over the socket failed. Has it been closed?
Hi.
How we can set ClientID when create connection ? I want pass dynamic ClientID per connection
Thank you
publishing a message is ok, but what about acknowledgment?
the scenario I want is -
publish command from laravel client to MQTT broker, which will send a command to esp2866, also the esp8266 device has a response topic, where the output of the command will publish. I want this response to ensure that command executed successfully...
kindly help.....
Hello, does it support auto reconnect in laravel-client?
I'm using RabbitMQ as broker and I wrote a Laravel command that runs this code:
class MyCommand extends Command
{
protected $signature = 'mqtt:listen';
private $mqtt;
public function __construct()
{
parent::__construct();
$this->mqtt = MQTT::connection();
}
public function handle()
{
$this->mqtt->subscribe('devices.+.write', function (string $topic, string $message) {
// Actually do stuff with the message
}, 2);
$this->mqtt->loop(true);
}
}
And I set up a supervisor configuration to run 4 instances of this command:
[program:mqtt-listen]
command = php /app/artisan mqtt:listen
process_name=%(program_name)s-%(process_num)s
numprocs = 4
startsecs = 0
autostart = true
autorestart = true
What happens is that I see 4 connections (and I suppose this is correct)
but I also see 4 different queues bond to the same exchange:
The result is that i receive 4 times the same message from 4 different queues.
What I want is to run 4 listeners to the same queue.
Is this possible and how?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.