Skip to main content

Serial Port to TCP and MQTT Bridge

Overview

This example demonstrates a powerful multi-protocol bridge that routes data from a serial port to both TCP and MQTT destinations. It showcases CycBox's ability to:

  • Parse binary protocols using the frame codec with checksums
  • Route messages between multiple connections simultaneously
  • Extract sensor data and publish to MQTT topics
  • Transform protocols using Lua scripting for custom logic

This is a common IoT pattern where sensor data from legacy serial devices needs to be forwarded to modern cloud services and local TCP applications.

Scenario

A PM2.5 air quality sensor is connected via serial port (e.g., /dev/ttyUSB0) and sends binary frames with a specific protocol. The requirements are:

  1. Parse the binary protocol with proper frame validation and checksum verification
  2. Forward complete frames to a local TCP server at 127.0.0.1:9000
  3. Extract PM2.5 values and publish them to MQTT topic cycbox/serial2mqtt
  4. Receive commands from MQTT topic cycbox/rx for device control

Configuration

The CycBox configuration consists of three independent connection:

id: "serial_assistant"
version: "1.8.0"
name: "Serial Assistant"
configs:
- # Config 0
app:
app_transport: serial
app_codec: frame_codec
app_transformer: disable
app_encoding: UTF-8
serial:
serial_port: /dev/ttyUSB0
serial_baud_rate: 9600
serial_data_bits: 8
serial_parity: none
serial_stop_bits: "1"
serial_flow_control: none
frame_codec:
frame_codec_prefix: 42 4d
frame_codec_header_size: 0
frame_codec_length_mode: u16_be
frame_codec_fixed_payload_size: 32
frame_codec_checksum_algo: sum16_be
frame_codec_checksum_scope: prefix_header_length_payload
frame_codec_tailer_length: 0
frame_codec_length_meaning: payload_checksum
frame_codec_suffix: ''
- # Config 1
app:
app_transport: tcp_client
app_codec: passthrough_codec
app_transformer: disable
app_encoding: UTF-8
tcp_client:
tcp_client_host: 127.0.0.1
tcp_client_port: 9000
tcp_client_timeout: 5000
tcp_client_keepalive: true
tcp_client_nodelay: true
- # Config 2
app:
app_transport: mqtt
app_codec: passthrough_codec
app_transformer: disable
app_encoding: UTF-8
mqtt:
mqtt_broker_url: "mqtt://broker.emqx.io:1883"
mqtt_client_id: cycbox_1bd79588-9987-4a21-987d-48eb449d225d
mqtt_username: ''
mqtt_password: ''
mqtt_use_tls: false
mqtt_ca_path: ''
mqtt_client_cert_path: ''
mqtt_client_key_path: ''
mqtt_subscribe_topics: cycbox/rx
mqtt_subscribe_qos: 0



Lua Script Logic

The Lua script implements the intelligent routing and data extraction logic:

Script Breakdown

-- Called for each received message
-- Access global 'message' object to read/modify message fields
-- MUST return true if message was modified, false otherwise
function on_receive()
local conn_id = message.connection_id
if conn_id == 0 then
local frame = message.frame
send_after(frame, 0, 1)
end
local payload = message.payload
if #payload == 26 then
local pm2_5_cf1 = read_u16_be(payload, 3)
message:add_int_value("PM2.5", pm2_5_cf1)
local values_json = message.values_json
mqtt_publish("cycbox/serial2mqtt", values_json, 0, false, 10, 2)
end
return true
end

How It Works

1. Message Routing (Lines 80-84)

local conn_id = message.connection_id
if conn_id == 0 then
local frame = message.frame
send_after(frame, 0, 1)
end
  • Checks if message came from serial port (conn_id == 0)
  • Uses send_after() to forward the complete binary frame to connection 1 (TCP client)
  • The delay of 0ms ensures immediate transmission

2. Sensor Data Extraction (Lines 85-91)

local payload = message.payload
if #payload == 26 then
local pm2_5_cf1 = read_u16_be(payload, 3)
message:add_int_value("PM2.5", pm2_5_cf1)
local values_json = message.values_json
mqtt_publish("cycbox/serial2mqtt", values_json, 0, false, 10, 2)
end
  • Validates payload size (26 bytes for this sensor protocol)
  • Extracts PM2.5 value from bytes 3-4 using big-endian 16-bit read
  • Adds extracted value to message metadata with label "PM2.5"
  • Converts values to JSON format
  • Publishes to MQTT topic with QoS 0 and 10-second timeout to connection 2