Упражнение MQTT: получение команд для светодиода
✅ Подпишитесь на color_topic(uuid).
✅ Запустите host_client параллельно, в отдельном терминале. host_client публикует color светодиода платы примерно раз в секунду.
✅ Проверьте, что подписка работает, выведя в лог информацию, полученную через топик.
✅ Реагируйте на команды светодиода: установите полученный цвет на плате с помощью led.set_pixel(/* received color here */).
intro/mqtt/exercise/solution/solution_publ_rcv.rs содержит решение. Запустить его можно командой:
cargo run --example solution_publ_rcv
Кодирование и декодирование полезной нагрузки сообщений
Команды светодиода платы состоят из трёх байтов, которые обозначают красный, зелёный и синий.
enum ColorDataсодержит топикcolor_topic(uuid)иBoardLed;- поле
data()структурыEspMqttMessageможно преобразовать с помощьюtry_from(). Сначала сообщение нужно привести к срезу:let message_data: &[u8] = &message.data();
#![allow(unused)]
fn main() {
// команда RGB-светодиода
if let Ok(ColorData::BoardLed(color)) = ColorData::try_from(message_data) { /* установить новый цвет здесь */ }
}
Публикация и подписка
EspMqttClient отвечает не только за публикацию, но и за подписку на топики.
#![allow(unused)]
fn main() {
let subscribe_topic = /* ... */;
client.subscribe(subscribe_topic, QoS::AtLeastOnce)
}
Обработка входящих сообщений
Параметр message_event в замыкании-обработчике имеет тип EspMqttEvent, у которого есть метод payload() для доступа к EventPayload.
Поскольку нас интересуют только успешно полученные сообщения:
#![allow(unused)]
fn main() {
let mut client =
EspMqttClient::new_cb(
&broker_url,
&mqtt_config,
move |message_event| match message_event.payload() {
Received { data, details, .. } => process_message(data, details, &mut led),
Error(e) => warn!("Received error from MQTT: {:?}", e),
_ => info!("Received from MQTT: {:?}", message_event.payload()),
},
)?;
}
В обработчике нужно обрабатывать сообщения Complete.
💡 Используйте Rust Analyzer, чтобы сгенерировать недостающие ветки match, или обработайте любой другой тип ответа, выведя его через info!().
#![allow(unused)]
fn main() {
fn process_message(data: &[u8], details: Details, led: &mut WS2812RMT) {
match details {
Complete => {
info!("{:?}", data);
let message_data: &[u8] = data;
if let Ok(ColorData::BoardLed(color)) = ColorData::try_from(message_data) {
info!("{}", color);
if let Err(e) = led.set_pixel(color) {
error!("Could not set board LED: {:?}", e)
};
}
}
_ => {}
}
}
}
💡 Используйте логгер, чтобы увидеть, что вы получаете, например info!("{}", color); или dbg!(color).
Дополнительные задания
Реализуйте MQTT с иерархическими топиками
✅ Выполняйте это, если всё остальное уже готово. Полного решения мы не даём: задача в том, чтобы проверить, как далеко вы продвинетесь самостоятельно.
Посмотрите common/lib/mqtt-messages:
✅ Реализуйте ту же процедуру, но с использованием иерархии MQTT. Подписывайтесь на все сообщения «command», комбинируя cmd_topic_fragment(uuid) с завершающим шаблоном #.
✅ Используйте enum Command вместо enum ColorData. enum Command представляет все возможные команды (здесь — только BoardLed).
✅ RawCommandData хранит последнюю часть топика сообщения (например, board_led в a-uuid/command/board_led). Его можно преобразовать в Command с помощью try_from.
#![allow(unused)]
fn main() {
// команда RGB-светодиода
let raw = RawCommandData {
path: command,
data: message.data(),
};
}
Посмотрите host-client:
✅ Нужно заменить color на command. Например, так:
#![allow(unused)]
fn main() {
let command = Command::BoardLed(color)
}
Другие задания
✅ Используйте serde_json, чтобы кодировать и декодировать данные сообщений в JSON.
✅ Отправьте с клиента-хоста несколько сообщений с большой полезной нагрузкой и обработайте их на микроконтроллере. Большие сообщения доставляются по частям вместо Details::Complete:
#![allow(unused)]
fn main() {
InitialChunk(chunk_info) => { /* первый фрагмент */},
SubsequentChunk(chunk_data) => { /* все последующие фрагменты */ }
}
💡 Не нужно различать входящие фрагменты по ID сообщения: в любой момент времени в пути может находиться не более одного сообщения.
Устранение неполадок
error: expected expression, found .при сборке host-клиента: обновите stable Rust до версии 1.58 или новее.- Не видно сообщений MQTT? Убедитесь, что все клиенты (плата и компьютер разработчика) используют один и тот же UUID (его видно в выводе логов).