Skip to content

[C] mqttv5 custom topics: publish client - #409

Merged
Ewerton Scaboro da Silva (ewertons) merged 4 commits into
mainfrom
c/mqttv5-custom-topics
Oct 11, 2026
Merged

Ewerton Scaboro da Silva (ewertons) merged 4 commits into
mainfrom
c/mqttv5-custom-topics

Conversation

@ewertons

Copy link
Copy Markdown
Contributor

Adds a client for publishing to the custom topics an mqttv5 hub allows through its topic templates (properties.mqttV5Settings.topicGroups[].topicTemplates).

API (inc/azure/iot/mqttv5/az_iot_custom_topic_client.h)

  • az_iot_mqttv5_custom_topic_client_init() / _deinit(): attaches to a connection, like the other mqttv5 clients. Fails with AZ_IOT_ERR_CONNECTION_PROFILE_MISMATCH on an mqttv3 connection.
  • az_iot_mqttv5_custom_topic_client_publish(): QoS 0 or 1, optional content type, user properties and message expiry.
    • The message is sent as given; the client adds no user properties of its own.
    • Completion reports the PUBACK result: AZ_IOT_ERR_PUBLISH_REFUSED when no template matches, AZ_IOT_ERR_MQTT when the adapter gives no reason.
  • az_iot_mqttv5_custom_topic_client_format_topic(): replaces {deviceId} with the connection's device id.
    • The variable is case-sensitive, and any other {/} is rejected, matching the hub's template syntax.
    • Returns AZ_IOT_ERR_NOT_CONNECTED until connected, because the device id can still change during provisioning.

Local topic validation

Topics the hub would refuse are rejected with AZ_IOT_ERR_INVALID_ARG, and nothing is sent:

  • + or # anywhere;
  • a leading $;
  • a first level of exactly ih, the hub's reserved namespace;
  • more than 256 bytes or more than 15 levels (the broker's limits);
  • malformed UTF-8.

Scope

  • Publish only. Custom topics cannot be subscribed to in this release.
  • No retain, response topic or correlation data. Fields can be appended later; zero keeps the current behaviour.

Also

  • mqttv5_custom_topic log component.
  • samples/mqttv5/custom_topic_publisher.
  • Docs: architecture feature table, logging, samples index, CHANGELOG.
  • Unit tests (18 cases) and the install test.

Validation

  • Linux, gcc 12, linux-gcc-debug preset with the az_mqtt adapter on: clean build, no warnings.
  • ctest: 53 of 59 suites pass, including the new az_iot_tests_mqttv5_custom_topic_client.
    • Failing: az_iot_conformance_paho_v3, az_iot_conformance_paho_v5, az_iot_conformance_paho_sign_negative, az_iot_conformance_az_mqtt_v3, az_iot_conformance_az_mqtt_v5 and az_iot_reconnect_integration. These are the broker-backed suites; this change does not touch the code they exercise.
    • paho_v5, az_mqtt_v5 and reconnect_integration fail the same way on unmodified main in the same environment. The other three were not re-run there.
  • eng/code-style.sh check (clang-format 18.1.8), check-layering.sh, check-banned-constructs.sh, check-log-components.sh, check-version.sh, check-hardening.sh: clean.
  • Not tested against a live hub. No test hub has topic templates configured yet.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The API lifecycle contract permits a leaked profile pin, and oversized templates can trigger an az_core precondition hang.

2 open findings
What changed in this PR

Adds an MQTT v5 custom-topic publishing client with validation, topic-template expansion, tests, documentation, and a sample.

Changes:

  • Introduces the public custom-topic client API and implementation.
  • Adds comprehensive unit/install coverage and build integration.
  • Adds a DPS-based publisher sample and supporting documentation.
File Description
c/​src/​mqttv5/​custom_topic_client.c Implements topic formatting, validation, and publishing.
c/​inc/​azure/​iot/​mqttv5/​az_iot_custom_topic_client.h Defines the public client API.
c/​inc/​azure/​iot/​az_iot.h Exposes the new API through the umbrella header.
c/​inc/​azure/​iot/​az_iot_log_components.h Adds the custom-topic log component.
c/​src/​CMakeLists.txt Builds the new implementation.
c/​tests/​unit/​mqttv5_custom_topic_client_test.c Tests lifecycle, publishing, validation, and formatting.
c/​tests/​install/​mqttv5_test.c Verifies installed-header usage.
c/​tests/​coverage-components.json Records custom-topic coverage scope.
c/​tests/​CMakeLists.txt Registers the unit suite.
c/​samples/​mqttv5/​custom_topic_publisher/​main.c Demonstrates DPS provisioning and publishing.
c/​samples/​mqttv5/​custom_topic_publisher/​README.md Documents sample setup and troubleshooting.
c/​samples/​mqttv5/​CMakeLists.txt Builds the sample.
c/​samples/​README.md Lists the sample.
c/​samples/​software_update/​esp32/​components/​azure-iot-sdk/​CMakeLists.txt Includes the source in ESP32 builds.
c/​docs/​logging.md Documents the log component.
c/​docs/​architecture.md Adds custom publishing to the feature matrix.
c/​CHANGELOG.md Announces the feature.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread c/src/mqttv5/custom_topic_client.c Outdated
Comment thread c/inc/azure/iot/mqttv5/az_iot_custom_topic_client.h

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The sample’s Paho adapter cannot produce the refusal status handled by its template-mismatch diagnostic.

0 open findings

2 resolved since last review
Previously missed (1)

In code that hasn't changed since last review

Medium severity Hub refusal diagnostic is unreachable with the registered MQTT adapter

c/​samples/​mqttv5/​custom_topic_publisher/​main.c:220

This branch is unreachable with the adapter this sample registers. az_iot_paho_factory_create_v5() routes every MQTT v5 publish failure to AZ_IOT_ERR_MQTT (c/adapters/paho/az_iot_mqtt_paho.c:940-946), so a no-template PUBACK will always fall through to the generic error and the advertised “hub refused” diagnostic is never shown. Either use a v5 adapter that preserves the PUBACK reason, or update Paho to classify response->reasonCode with az_iot_mqtt_puback_result() and keep the sample/README aligned.

🧠 Review effort: Balanced

Copilot AI balanced review requested due to automatic review settings October 11, 2026 04:46
@ewertons

Copy link
Copy Markdown
Contributor Author

Re: unreachable "hub refused" diagnostic in the sample: correct for Paho, which reports every failed MQTT v5 publish as AZ_IOT_ERR_MQTT. Classifying Paho's PUBACK reason code is a separate adapter change. Here the sample and its README now say that with Paho a refusal surfaces as AZ_IOT_ERR_MQTT; the AZ_IOT_ERR_PUBLISH_REFUSED branch stays for adapters that report it (az_mqtt does).

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The new public MQTT v5 API and service-specific behavior were not validated against a live hub configured with topic templates.

0 open findings

🧠 Review effort: Balanced

AZ_NODISCARD az_iot_result az_iot_mqttv5_custom_topic_client_publish(
az_iot_mqttv5_custom_topic_client* client,
const az_iot_mqttv5_custom_topic_message* message,
az_iot_telemetry_send_callback callback,

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why telemetry? just because it can be reused?
It better be typedef'ed into a specific type name, in case we need to separate things in the future. Push back if you will

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, done in 8cdf6cf: publish() now takes its own az_iot_mqttv5_custom_topic_publish_callback (same signature), so it can diverge from telemetry later. The header no longer includes az_iot_message.h.

Comment thread c/src/mqttv5/custom_topic_client.c Outdated
* @return false, appending nothing, when they cannot fit @p out_size (at most INT32_MAX), which
* also keeps @p length within the int32_t az_span_create() takes.
*/
static bool append_literal(

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a good practice to mix public and static functions like this.
Functions shall be defined in the source code in this order:
static internal function prototype defines
public functions
static internal function implementations.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 8cdf6cf: static prototypes first, then the public functions, then the static implementations. No logic changed.

Copilot AI balanced review requested due to automatic review settings October 11, 2026 06:01

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

It introduces a public preview-service API and wire behavior that has not been validated against a live configured hub.

0 open findings

🧠 Review effort: Balanced

Add az_iot_mqttv5_custom_topic_client for publishing to the custom topics
an mqttv5 hub's topic templates allow.

- publish(): QoS 0 or 1, content type, user properties, message expiry.
  Sent as given; the client adds no user properties.
- format_topic(): replaces {deviceId} with the connection's device id.
  Other {...} tokens are rejected, as on the hub.
- Topics the hub would refuse are rejected locally: wildcards, a leading
  '$', a first level of "ih", more than 256 bytes or 15 levels, or
  malformed UTF-8.
- Publish only: custom topics cannot be subscribed to.

Includes unit tests, the mqttv5/custom_topic_publisher sample and docs.
…ract

- format_topic(): a literal run that cannot fit the output fails with
  AZ_IOT_ERR_NOT_ENOUGH_SPACE before it reaches az_span_create().
- init(): document that the client must not already be initialized and
  that the connection must outlive it.
- ci-c coverage: expect 53 test suites.
…usals yet

The Paho adapter reports every failed MQTT v5 publish as AZ_IOT_ERR_MQTT,
so with it a topic no template matches does not reach the sample's
AZ_IOT_ERR_PUBLISH_REFUSED branch. Say so in the sample and its README.
- publish() takes az_iot_mqttv5_custom_topic_publish_callback instead of
  reusing the telemetry callback type, so the two can diverge.
- custom_topic_client.c: static prototypes, then public functions, then
  static implementations.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

It introduces a public preview-protocol API whose live IoT Hub behavior has not yet been validated.

1 open finding

🧠 Review effort: Balanced

Comment on lines +103 to +107
* @retval AZ_IOT_ERR_INVALID_ARG A NULL argument, or a `{` or `}` that is not part of
* `{deviceId}`.
* @retval AZ_IOT_ERR_NOT_CONNECTED The connection is not connected, so the device id is not
* final.
* @retval AZ_IOT_ERR_NOT_ENOUGH_SPACE @p out_size is too small.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed/Approved

@ewertons
Ewerton Scaboro da Silva (ewertons) merged commit 6f8860c into main Oct 11, 2026
54 checks passed
@ewertons
Ewerton Scaboro da Silva (ewertons) deleted the c/mqttv5-custom-topics branch October 11, 2026 07:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants