[PLUGIN] MQTT Client Plugin (Volumio 4) - Weekend Project

Dear Volumionauts,

A weekend project that scratches an itch.

There was a recent ask about MQTT support for Volumio 4. The old status2mqtt plugin is abandoned - original author moved on to other solutions. Rather than let it sit, I put together a fresh implementation over the weekend.

What it does:

  • Publishes Volumio state to MQTT broker (track info, playback status, volume, etc.)
  • Subscribes to command topics (play, pause, stop, next, prev, volume, seek, etc.)
  • Works with Home Assistant, OpenHAB, Node-RED, or any MQTT broker
  • Supports TLS/SSL and certificate authentication
  • Customizable topic structure (default: volumio/{device_id}/…)

What it is NOT:

  • A polished, fully supported product
  • Something I can commit to maintaining long-term
  • Tested on every possible configuration

I already maintain several Volumio plugins as a volunteer in my spare time. This one exists because it was not difficult to scribble together for an average nerd on a Saturday evening. It works for me. It might work for you.

Available in the plugin store once publishing completes.

Source will be available. If you want to fork it, adopt it, improve it - go ahead. Pull requests welcome. If someone wants to take over as primary maintainer, even better.

Use it, break it, fix it, share it.

Kind Regards,

2 Likes

Dear Volumionauts,

MQTT Client Plugin - User Guide

This guide covers basic setup and usage. For complete documentation including Home Assistant and OpenHAB examples, see the full README.

QUICK START

  1. Install plugin from store (beta channel)
  2. Configure broker connection (host, port, credentials if needed)
  3. Enable plugin
  4. Verify connection in Volumio logs or your MQTT client

Minimum required settings:

  • Broker Host (IP or hostname of your MQTT broker)
  • Broker Port (1883 for unencrypted, 8883 for TLS)

UNDERSTANDING TOPICS

MQTT uses a topic hierarchy like folders. This plugin uses:

{base_topic}/{device_id}/…

Default base_topic is ā€œvolumioā€. Device ID defaults to your Volumio hostname.

Example: If your Volumio is named ā€œkitchenā€, topics will be:

  • volumio/kitchen/status (full state as JSON)
  • volumio/kitchen/status/title (current track)
  • volumio/kitchen/status/volume (0-100)
  • volumio/kitchen/set/play (send command here)

RECEIVING STATE (what Volumio publishes)

State topics under: volumio/{device_id}/status/

  • state - play, pause, stop
  • title - current track
  • artist - current artist
  • album - current album
  • volume - 0 to 100
  • mute - true or false
  • seek - position in milliseconds
  • duration - track length in milliseconds

Full JSON state also published to: volumio/{device_id}/status

SENDING COMMANDS (control Volumio)

Command topics under: volumio/{device_id}/set/

  • play - start playback (no payload needed)
  • pause - pause playback
  • stop - stop playback
  • toggle - toggle play/pause
  • next - next track
  • previous (or prev) - previous track
  • volume - set volume (payload: 0-100)
  • volumeup (or volup) - increase volume
  • volumedown (or voldown) - decrease volume
  • mute - payload: true, false, or toggle
  • seek - payload: position in milliseconds
  • repeat - payload: true, false, or toggle
  • random (or shuffle) - payload: true, false, or toggle
  • clear - clear queue

Example: To set volume to 50, publish ā€œ50ā€ to volumio/kitchen/set/volume

MULTI-ROOM / GROUPS

Enable group topic in settings and set a group ID (example: ā€œdownstairsā€).

Commands sent to volumio/group/downstairs/set/play will control all instances subscribed to that group.

TLS / CERTIFICATES

For secure connections:

  1. Set port to 8883
  2. Enable TLS in settings
  3. Provide paths to certificate files if required by your broker

TROUBLESHOOTING

  • Enable Debug Logging in plugin settings
  • Check logs: journalctl -f -u volumio
  • Test broker connectivity: mosquitto_sub -h {broker_ip} -t ā€œvolumio/#ā€ -v
  • Verify firewall allows port 1883 or 8883

Kind Regards,

1 Like

@nerd - As promised, some initial feedback.

Once configured, as hoped it’s a full drop-in replacement for the old status2MQTT plugin.
Thus far running happily on three systems (2x Pi Zero 2W and 1s Pi3) and feeding the status etc back to my network and Home Assistant set-up perfectly, and fully controllable by HASS.

The only thing for me is the MQTT control of the devices.
I gave it a quick run-out, and whilst it seems to work, the devices take a while to respond (trying to toggle them). Just to confirm if I’m doing it right, tried sending volumio/radiopi/set/toggle/ with the payload of ā€œtoggleā€ (based on your two examples above - I’m assuming the payload is ignored here anyway).

I’ll play with it some more - I think it’s working but the lag (probably due to being a Pi Zero2) is making it a bit difficult to be fully certain.

Great job anyway though, especially for a quick weekend project :smiley:

Hi @nerd

I have installed your MQTT plugin and connected it to my broker. I use iobroker for my smart home and the MQTT broker/client adapter. I can receive data from Volumio in iobroker, but I can’t send control signals. Is this due to iobroker, or could it be your plugin? As I said, I receive the current data from Volumio every 10 seconds, but I can’t send any commands via the data points.

Best regards

Thanks for the feedback and testing, both of you. I have reviewed the code and I can confirm the command handling logic is working correctly - but both issues appear to be topic structure problems. Let me explain what is happening and how to fix it.


@DarrenHill - Toggle command with trailing slash

WHAT YOU ARE DOING WRONG:

You are publishing to: volumio/radiopi/set/toggle/
(note the trailing slash at the end)

The plugin subscribes to: volumio/radiopi/set/+

In MQTT, the + wildcard matches exactly ONE topic level. Your trailing slash creates an EXTRA empty level:

Your topic:      volumio / radiopi / set / toggle / (empty)
                    1        2        3      4        5

Subscription:    volumio / radiopi / set / +
                    1        2        3     4

The subscription pattern expects 4 levels. Your topic has 5 levels. The message never reaches the plugin because MQTT considers these as non-matching.

WHAT YOU SHOULD DO INSTEAD:

Remove the trailing slash. Correct examples:

Topic: volumio/radiopi/set/toggle
Payload: (empty or anything - ignored for toggle)

Topic: volumio/radiopi/set/play
Payload: (empty or anything)

Topic: volumio/radiopi/set/volume
Payload: 50

The ā€œlagā€ you experienced is likely from inconsistent trailing slashes in your testing - some attempts matched, others did not.


@Mustang65 - ioBroker cannot send commands

WHAT IS LIKELY HAPPENING:

You can receive state data (plugin publishes to your broker successfully) but cannot send commands. This means the plugin is not receiving your messages, which points to a topic mismatch.

WHAT TO CHECK:
  1. Verify your exact topic structure in ioBroker. The plugin expects:
{base_topic}/{device_id}/set/{command}

For example, if your base_topic is ā€œvolumioā€ and device_id is ā€œmyplayerā€:

volumio/myplayer/set/play
volumio/myplayer/set/pause
volumio/myplayer/set/toggle
volumio/myplayer/set/volume  (payload: 0-100)
  1. Check your plugin configuration in Volumio:

    • What is your ā€œBase Topicā€ setting?
    • What is your ā€œDevice IDā€ setting? (if blank, it uses hostname)
  2. Alternative JSON command format - you can also send to the /command topic:

Topic: volumio/myplayer/command
Payload: {"command": "play"}

Topic: volumio/myplayer/command
Payload: {"command": "volume", "value": 50}
  1. Enable debug logging in the plugin (Debug Settings section) and check Volumio logs:
journalctl -f -u volumio

Look for lines starting with [MQTT-Debug]. When you send a command, you should see:

[MQTT-Debug] Received message on topic: ... - payload: ...
[MQTT-Debug] Executing command: ... with value: ...

If you see NO log entries when sending - the topic does not match the subscription.


[QUICK REFERENCE - Valid command topics]

Assuming base_topic=volumio and device_id=myplayer:

PLAYBACK:
  volumio/myplayer/set/play
  volumio/myplayer/set/pause
  volumio/myplayer/set/toggle
  volumio/myplayer/set/stop
  volumio/myplayer/set/next
  volumio/myplayer/set/previous

VOLUME:
  volumio/myplayer/set/volume      payload: 0-100
  volumio/myplayer/set/mute        payload: true/false/toggle (or empty)
  volumio/myplayer/set/unmute
  volumio/myplayer/set/volumeup
  volumio/myplayer/set/volumedown

OTHER:
  volumio/myplayer/set/seek        payload: position in seconds
  volumio/myplayer/set/repeat      payload: true/false (or empty to toggle)
  volumio/myplayer/set/random      payload: true/false (or empty to toggle)
  volumio/myplayer/set/clear

JSON FORMAT (alternative):
  volumio/myplayer/command         payload: {"command": "play"}
  volumio/myplayer/command         payload: {"command": "volume", "value": 75}
IMPORTANT: No trailing slashes on any topic.

Let me know if you still have issues after checking these points. If ioBroker problems persist, please share:

  • Your exact plugin configuration (base_topic, device_id)
  • The exact topic path ioBroker is publishing to
  • Any debug log output from the plugin

Kind Regards,

Hi @nerd

Thanks for your reply. I found the ā€œerror.ā€ The error is sitting in front of the keyboard. :slight_smile: If you enter the correct commands and pay attention to the syntax, it works perfectly. I can now control Voluimio via MQTT.

Thanks again,

Best regards

@nerd - thanks, that clarifies things a bit.

Without any trailing slashes it does mostly work, although it’s a bit hit-and-miss as it needs a certain minimum delay between sending commands for it to respond.

Nothing to worry about though in my case, as I’m controlling via Home Assistant and that works perfectly with MQTT being used to read stuff back and distribute status to other things on my network.

Hi @nerd

I installed the MQTT plugin a few days ago and integrated Volumio into my smart home. The commands are coming through and the states are also coming back cleanly. However, I have noticed that when I listen to Internet radio or MP3s locally, I can control Volumio via MQTT (start, pause, stop, etc.). However, when I listen to Tidal via Volumio, the MQTT command does not seem to work. The display in the browser shows that the music is paused, but the seek bar and the track continue to run in the ā€œbackground.ā€ It seems as if the MQTT command only applies to the Volumio interface and is not passed on to Tidal. Could that be the case?

Oh, and I’m using Tidal directly in Volumio, not Tidal Connect!

Kind regards

Hey @Mustang65,

Thanks for the detailed report. This helps narrow down what is happening.

Clarification:

The MQTT plugin is a passthrough - it simply calls standard Volumio commandRouter methods:

self.commandRouter.volumioPause();
self.commandRouter.volumioPlay();

These are the exact same methods called by:

  • Volumio web UI buttons
  • Volumio REST API
  • IR remote plugin
  • Any other control method

The MQTT plugin has no special knowledge of Tidal, Qobuz, Spotify, or any other streaming service. It talks to Volumio core, and Volumio core talks to the service plugins.

Working theory:

Tidal is a proprietary MyVolumio plugin - it is not a community plugin and I have no access to its source code. The Tidal plugin has its own playback engine and state management.

There can be state synchronization issues between:

  • Volumio core state (what the UI displays)
  • Streaming service state (what is actually playing)

If the UI shows ā€œpausedā€ but audio continues, Volumio core received the command and updated its state - but the Tidal service plugin may not have acted on it properly. This would be a Tidal integration issue, not an MQTT issue.

Questions:

  1. When Tidal is playing, does pressing the PAUSE button directly in the Volumio web UI work correctly?

    • If NO - this confirms a Tidal plugin issue, nothing to do with MQTT
    • If YES - we need to investigate further
  2. Does the same problem occur with other premium services (Qobuz, Spotify Connect) if you have access to them?

  3. Is this reproducible 100% of the time, or intermittent?

Please capture and share logs:

First, enable debug logging in the MQTT plugin settings (Debug Settings section).

Then reproduce the issue:

  1. Start Tidal playback
  2. Send pause command via MQTT
  3. Note the time when you sent the command

Then retrieve logs via the Volumio dev page:

  1. Open http://volumio.local/dev (or use your device IP)
  2. Click ā€œSend logā€
  3. Share the URL you receive

This is the correct method for Volumio log retrieval - see: How to send a log link for a bug report?

The logs will show whether:

  • MQTT received and executed the command (my plugin - look for [MQTT-Debug] entries)
  • Volumio core processed it correctly
  • Tidal service responded appropriately

If the logs show [MQTT-Debug] Executing command: pause - then my plugin did its job correctly, and the issue lies with either Volumio core or the Tidal plugin. Since Tidal is a proprietary MyVolumio plugin, you would need to report that to Volumio support directly.

Kind Regards,

Hi @nerd

Sorry for the late reply.

When I start/stop/pause Tidal via the UI, it responds as it should. The output stops, the seek bar stops, and my streamer’s display goes to screensaver mode.

When I send the stop/pause command via MQTT, the output from the streamer stops, but the seek bar and timecode continue to run and the screen saver does not activate. This behavior can be reproduced with Tidal, even on other Volumio instances (I have 3 in use). I do not have access to Qubuz and Spotify.

Here is the log link:

http://logs.volumio.org/volumio/Uu6IphD.html

The pause command via MQTT came at 1:31 a.m.

Perhaps you can find out more from the log; it would be interesting to find out where the communication breaks down.

Best regards

By the way, after sending the MQTT command, Tidal can no longer be operated via the UI. The UI displays ā€œPause,ā€ Tidal appears to continue running, but can no longer be controlled. Only after switching to another source can Tidal be controlled again via the UI.

Hey @Mustang65,

Thank you for the detailed log and follow-up information - this was exactly what I needed to track down the root cause.

This is a Volumio core issue, not an MQTT plugin bug. The MQTT plugin is working correctly - commands are being received and executed properly.

I traced through the Volumio backend source code (CoreStateMachine, CoreCommandRouter, MPD plugin) and found the problem in how Volumio handles the stop command for streaming services that use ā€œconsume modeā€ (Tidal, Qobuz, webradio).

When stop is called, the state machine executes this sequence:

CoreStateMachine.stop()
  -> setConsumeUpdateService(undefined)   <-- clears consume mode context
  -> currentStatus = 'stop'
  -> serviceStop()
     -> ControllerTidal::stop()
     -> ControllerMpd::stop()

The consume mode context is cleared BEFORE the Tidal plugin processes the stop. This breaks the routing for subsequent commands.

Compare to pause (which works correctly):

CoreStateMachine.pause()
  -> currentStatus = 'pause'
  -> servicePause()                       <-- no clearing of consume mode
     -> ControllerTidal::pause()
     -> ControllerMpd::pause()

Your log at 01:32:09 shows exactly what happens when UI stops working:

CoreCommandRouter::volumioPause
CoreStateMachine::pause
(nothing else - no servicePause, no ControllerTidal::pause)

The pause() method has a guard: if (currentStatus === 'play'). After MQTT stop sets currentStatus to ā€˜stop’, this guard fails and pause() returns without doing anything. The UI becomes unresponsive.

In summary:

  • The audio stopping is correct (backend worked)
  • The seek bar continuing and UI becoming unresponsive is a state synchronization issue in Volumio core
  • This affects any external control method (MQTT, REST API, etc.) that calls volumioStop() for streaming services

I have prepared a workaround in the MQTT plugin that detects streaming services and uses pause instead of stop to preserve the consume mode context. This is not ideal (stop behaves like pause for streaming services) but it prevents the UI from becoming unresponsive.

Would you be willing to test this workaround? It requires manual file replacement via SSH - outside of the normal plugin store delivery. If you are comfortable with that, I will provide the modified file and instructions.

Regardless of testing, I recommend opening a bug report with Volumio support referencing this thread and your log (http://logs.volumio.org/volumio/Uu6IphD.html).

Kind regards

1 Like

Hi @nerd

I’m glad I could help.

I can test the workaround, but I’m not very familiar with the console. SSH is no problem, I just need instructions from you on how to swap the file. Then it shouldn’t be a problem. Feel free to send me a private message if you don’t want this to be public.

I will also contact Volumio support and refer them to this thread.

Best regards,

Hey @Mustang65,

Thank you for testing and confirming the fix. Plugin v1.0.2 with the workaround has been published to the plugin store.

You can update via Plugins > Installed Plugins > MQTT Client > Update, or uninstall and reinstall from the store.

If you previously applied the manual fix, you may want to do a clean reinstall to ensure all files are in sync.

Thanks again for your help tracking this down and for reporting the issue to Volumio support.

Kind regards

Hi @nerd

I got a reply from Volumio support. They closed the ticket, stating that our case involved third-party inquiries. Support doesn’t seem to be interested in pursuing the matter further.

I also noticed that when you use the sleep function (zzz button) in the Volumio start menu, it only works with Volumio itself, but not with Tidal. It was the same with the MQTT command.

Kind regards,