From: aaronk6 Date: Sun, 17 Mar 2024 12:12:55 +0000 (+0100) Subject: Add support for MQTT autodiscovery X-Git-Tag: 4.3.5^2~20^2~4 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cda315b6aac424656cf7155a0adb2ffc5b4d4060;p=thirdparty%2Fshairport-sync.git Add support for MQTT autodiscovery --- diff --git a/common.h b/common.h index 9de26f63..6a341f7b 100644 --- a/common.h +++ b/common.h @@ -175,6 +175,8 @@ typedef struct { int mqtt_publish_parsed; int mqtt_publish_cover; int mqtt_enable_remote; + int mqtt_enable_autodiscovery; + char *mqtt_autodiscovery_prefix; char *mqtt_empty_payload_substitute; #endif uint8_t ap1_prefix[6]; diff --git a/mqtt.c b/mqtt.c index fd172161..2b9bd5b2 100644 --- a/mqtt.c +++ b/mqtt.c @@ -94,6 +94,52 @@ void on_connect(struct mosquitto *mosq, __attribute__((unused)) void *userdata, snprintf(remotetopic, strlen(config.mqtt_topic) + 8, "%s/remote", config.mqtt_topic); mosquitto_subscribe(mosq, NULL, remotetopic, 0); } + + // send autodiscovery messages if enabled + if (config.mqtt_enable_autodiscovery && config.mqtt_publish_parsed) { + send_autodiscovery_messages(mosq); + } +} + +void send_autodiscovery_messages(struct mosquitto *mosq) { + const char *autodiscovery_prefix = (config.mqtt_autodiscovery_prefix != NULL) ? + config.autodiscovery_prefix : "homeassistant"; + char base_topic[256]; + snprintf(base_topic, sizeof(base_topic), "%s/sensor/shairport-sync-", autodiscovery_prefix); + + char full_topic[256]; + char payload[1024]; + const char *device_name = config.service_name; + + const char *sensors[] = { + "artist", "album", "title", "genre", "format", "track_id", + "client_ip", "client_name", "volume", "is_active", "is_playing", NULL + }; + // Human-readable names + const char *sensor_names[] = { + "Artist", "Album", "Title", "Genre", "Format", "Track ID", + "Client IP", "Client Name", "Volume", "Is Active", "Is Playing", NULL + }; + + for (int i = 0; sensors[i] != NULL; i++) { + snprintf(full_topic, sizeof(full_topic), "%s%s/config", base_topic, sensors[i]); + snprintf(payload, sizeof(payload), + "{\n" + " \"name\": \"%s\",\n" + " \"state_topic\": \"%s/%s\",\n" + " \"icon\": \"mdi:music-note\",\n" + " \"unique_id\": \"shairport-sync-%s\",\n" + " \"device\": {\n" + " \"identifiers\": [\"shairport-sync\"],\n" + " \"name\": \"%s\",\n" + " \"model\": \"Shairport-Sync\",\n" + " \"manufacturer\": \"shairport-sync\"\n" + " }\n" + "}", sensor_names[i], config.mqtt_topic, sensors[i], sensors[i], device_name); + + mosquitto_publish(mosq, NULL, full_topic, strlen(payload), payload, 0, true); + debug(2, "[MQTT Autodiscovery]: Published autodiscovery for %s", sensor_names[i]); + } } // helper function to publish under a topic and automatically append the main topic diff --git a/scripts/shairport-sync.conf b/scripts/shairport-sync.conf index 517a7560..8423b807 100644 --- a/scripts/shairport-sync.conf +++ b/scripts/shairport-sync.conf @@ -285,6 +285,8 @@ mqtt = // Currently published topics:artist,album,title,genre,format,songalbum,volume,client_ip, // Additionally, messages at the topics play_start,play_end,play_flush,play_resume are published // publish_cover = "no"; //whether to publish the cover over mqtt in binary form. This may lead to a bit of load on the broker +// enable_autodiscovery = "no"; //whether to publish an autodiscovery message to automatically appear in Home Assistant +// autodiscovery_prefix = "homeassistant"; //string to prepend to autodiscovery topic // enable_remote = "no"; //whether to remote control via MQTT. RC is available under `topic`/remote. // Available commands are "command", "beginff", "beginrew", "mutetoggle", "nextitem", "previtem", "pause", "playpause", "play", "stop", "playresume", "shuffle_songs", "volumedown", "volumeup" }; diff --git a/shairport.c b/shairport.c index 1060e0b7..87ac0ea7 100644 --- a/shairport.c +++ b/shairport.c @@ -1300,6 +1300,10 @@ int parse_options(int argc, char **argv) { if (config.mqtt_publish_cover && !config.get_coverart) { die("You need to have metadata.include_cover_art enabled in order to use mqtt.publish_cover"); } + config_set_lookup_bool(config.cfg, "mqtt.enable_autodiscovery", &config.mqtt_enable_autodiscovery); + if (config_lookup_string(config.cfg, "mqtt.autodiscovery_prefix", &str)) { + config.mqtt_autodiscovery_prefix = (char *)str; + } config_set_lookup_bool(config.cfg, "mqtt.enable_remote", &config.mqtt_enable_remote); if (config_lookup_string(config.cfg, "mqtt.empty_payload_substitute", &str)) { if (strlen(str) == 0) @@ -2550,6 +2554,7 @@ int main(int argc, char **argv) { debug(1, "mqtt will%s publish parsed metadata.", config.mqtt_publish_parsed ? "" : " not"); debug(1, "mqtt will%s publish cover Art.", config.mqtt_publish_cover ? "" : " not"); debug(1, "mqtt remote control is %sabled.", config.mqtt_enable_remote ? "en" : "dis"); + debug(1, "mqtt autodiscovery is %sabled.", config.mqtt_enable_autodiscovery ? "en" : "dis"); #endif #ifdef CONFIG_CONVOLUTION