项目:物联网网关

完整 IoT 网关:采集 Modbus / I2C / GPIO 数据,通过 MQTT 上传云端,支持反向控制。

一、目标

二、架构

┌─────────────────────────────────────┐
│         应用进程                     │
├─────────────────────────────────────┤
│ MQTT   │  Config │ Storage │ Logger │
├───────┴──────────┴───────┴────────┤
│        数据聚合 & 业务逻辑          │
├─────────────────────────────────────┤
│ Modbus  │ I2C  │ GPIO │ RS232/485  │
│ 主/从   │ 传感器│ 开关 │ GPS/UART  │
└─────────────────────────────────────┘

三、核心代码结构

gateway/
├── main.c
├── config.c
├── config.h
├── mqtt_client.c
├── modbus_master.c
├── sensor_i2c.c
├── storage.c
├── logger.c
├── web_server.c
├── cmd.h
└── Makefile

四、JSON 配置

{
  "device": {
    "id": "gw001",
    "name": "Lab Gateway"
  },
  "mqtt": {
    "host": "broker.example.com",
    "port": 1883,
    "user": "device",
    "pass": "xxx",
    "tls": false
  },
  "modbus": [
    {"port": "/dev/ttymxc0", "baud": 9600, "devices": [
      {"addr": 1, "func": "input_register", "reg": 100, "qty": 2, "name": "temperature"}
    ]}
  ],
  "sensors": [
    {"type": "htu21d", "bus": 1, "addr": 0x40, "name": "temp_hum"}
  ],
  "upload_interval": 30,
  "web_port": 8080
}

五、MQTT 上报

// 上报数据
void publish_sensor(const char *name, double value)
{
    char topic[128];
    snprintf(topic, sizeof(topic), "devices/%s/data/%s", device_id, name);

    char payload[256];
    snprintf(payload, sizeof(payload),
        "{\"name\":\"%s\",\"value\":%.2f,\"ts\":%lld}",
        name, value, (long long)time(NULL));

    MQTTClient_message msg = {
        .payload = payload,
        .payloadlen = strlen(payload),
        .qos = 1,
        .retained = 0,
    };
    MQTTClient_publishMessage(client, topic, &msg, NULL);
}

六、MQTT 反向控制

void on_msg(char *topic, MQTTClient_message *msg)
{
    char cmd[256];
    snprintf(cmd, sizeof(cmd), "%.*s", msg->payloadlen, (char*)msg->payload);
    // 解析 JSON
    cJSON *root = cJSON_Parse(cmd);
    cJSON *act = cJSON_GetObjectItem(root, "action");

    if (strcmp(act->valuestring, "set") == 0) {
        cJSON *relay = cJSON_GetObjectItem(root, "relay");
        cJSON *val = cJSON_GetObjectItem(root, "value");
        set_relay(relay->valueint, val->valueint);
    }

    cJSON_Delete(root);
    MQTTClient_freeMessage(&msg);
    MQTTClient_free(topic);
}

七、Modbus Master

// 用 libmodbus
modbus_t *ctx = modbus_new_rtu("/dev/ttymxc0", 9600, 'N', 8, 1);
modbus_set_slave(ctx, 1);
modbus_connect(ctx);

uint16_t tab_reg[32];
int rc = modbus_read_input_registers(ctx, 100, 2, tab_reg);
if (rc == 2) {
    float temp = tab_reg[0] / 10.0;
    publish_sensor("temperature", temp);
}

modbus_close(ctx);
modbus_free(ctx);

八、数据采集调度

static void *collector_thread(void *arg)
{
    while (running) {
        // Modbus
        for (int i = 0; i < config.modbus_count; i++) {
            poll_modbus(&config.modbus[i]);
        }
        // I2C 传感器
        for (int i = 0; i < config.sensor_count; i++) {
            poll_i2c_sensor(&config.sensors[i]);
        }
        sleep(config.upload_interval);
    }
    return NULL;
}

九、本地存储(SQLite)

#include <sqlite3.h>

sqlite3 *db;
sqlite3_open("/var/lib/gateway.db", &db);
sqlite3_exec(db,
    "CREATE TABLE IF NOT EXISTS data ("
    "id INTEGER PRIMARY KEY AUTOINCREMENT,"
    "ts INTEGER, name TEXT, value REAL)",
    NULL, NULL, NULL);

sqlite3_stmt *stmt;
sqlite3_prepare_v2(db,
    "INSERT INTO data (ts, name, value) VALUES (?,?,?)", -1, &stmt, NULL);
sqlite3_bind_int64(stmt, 1, time(NULL));
sqlite3_bind_text(stmt, 2, "temp", -1, SQLITE_STATIC);
sqlite3_bind_double(stmt, 3, 25.6);
sqlite3_step(stmt);
sqlite3_finalize(stmt);

sqlite3_close(db);

十、Web 配置界面

用 mongoose + 静态文件:

if (mg_match(hm->uri, mg_str("/api/config"), NULL)) {
    if (hm->method.len == 4 && !memcmp(hm->method.buf, "GET", 3)) {
        char *json = config_to_json();
        mg_http_reply(c, 200, "Content-Type: application/json\r\n", "%s", json);
        free(json);
    } else if (hm->method.len == 4 && !memcmp(hm->method.buf, "POST", 4)) {
        // 解析 body
        char body[1024] = { 0 };
        memcpy(body, hm->body.buf, hm->body.len);
        config_from_json(body);
        save_config();
        mg_http_reply(c, 200, "", "OK");
    }
}

十一、设备接入云端

云平台 协议
AWS IoT Core MQTT over TLS
阿里云 LinkKit MQTT
华为云 IoTDA MQTT/HTTPS/LwM2M
腾讯云 IoT Explorer MQTT
Azure IoT Hub MQTT/AMQP
EMQ X 自建 MQTT broker
Mosquitto 自建

十二、远程升级

# OTA:监听 MQTT 升级指令
if (msg topic == "device/upgrade") {
    if (confirm) {
        wget http://server/firmware.swu
        swupdate -i firmware.swu -e stable
    }
}

十三、调试

# MQTT 调试
mosquitto_sub -h broker -t '#' -v
mosquitto_pub -h broker -t 'cmd' -m '...'

# Modbus 调试
mbpoll -m rtu -b 9600 -a 1 /dev/ttymxc0 -r 100

# 网络
tcpdump -i eth0 -w cap.pcap
wireshark cap.pcap