{"id":45957941,"url":"https://github.com/zeroonelab/embatlink","last_synced_at":"2026-03-03T05:01:15.548Z","repository":{"id":340926577,"uuid":"1168139310","full_name":"ZeroOneLab/EmbATlink","owner":"ZeroOneLab","description":"轻量解耦的嵌入式 AT 指令驱动框架，支持多设备并行、主动发送 / 被动监听，跨平台易移植，适配 STM32 等 MCU，裸机 / RTOS 均兼容。","archived":false,"fork":false,"pushed_at":"2026-02-28T09:34:58.000Z","size":513,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-02-28T15:50:24.632Z","etag":null,"topics":["at-command","at-driver","embedded","iot","stm32","uart"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ZeroOneLab.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-27T03:47:41.000Z","updated_at":"2026-02-28T09:26:34.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/ZeroOneLab/EmbATlink","commit_stats":null,"previous_names":["zeroonelab/embatlink"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/ZeroOneLab/EmbATlink","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ZeroOneLab%2FEmbATlink","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ZeroOneLab%2FEmbATlink/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ZeroOneLab%2FEmbATlink/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ZeroOneLab%2FEmbATlink/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ZeroOneLab","download_url":"https://codeload.github.com/ZeroOneLab/EmbATlink/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ZeroOneLab%2FEmbATlink/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30032355,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-03T03:27:35.548Z","status":"ssl_error","status_checked_at":"2026-03-03T03:27:09.213Z","response_time":61,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["at-command","at-driver","embedded","iot","stm32","uart"],"created_at":"2026-02-28T13:38:29.346Z","updated_at":"2026-03-03T05:01:15.525Z","avatar_url":"https://github.com/ZeroOneLab.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# EmbATlink\n\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\n一款**高通用性、分层解耦**的AT指令驱动框架，专为嵌入式MCU设计，解决物联网开发中多模组AT指令代码冗余、跨平台移植困难、多路设备并行通信难等问题，支持主动指令发送+被动事件监听，适配STM32等主流MCU平台，裸机/RTOS环境均兼容。\n\n## 关键词\n\nAT command, AT driver, EmbATlink, 串口驱动, 物联网AT指令, 分层解耦AT驱动\n\n## 命名说明\n\n本项目命名为`EmbATlink`，其中：\n\n- `Emb` = Embedded（嵌入式），代表框架的应用场景为嵌入式MCU开发；\n\n- `AT` = AT指令，是物联网模组通用的控制通信协议；\n\n- `link` = 链路/连接，代表框架作为主机与AT模组之间的通信桥梁；\n\n因此`EmbATlink`本质是**标准化、可扩展的嵌入式AT指令驱动框架**，区别于传统项目中零散的AT指令收发代码。\n\n## 🌟 核心特性\n\n✅ **分层解耦设计**：核心逻辑与硬件操作完全分离，移植仅需修改硬件抽象层，无需改动核心代码\n\n✅ **多设备支持**：通过LUN（逻辑单元号）标识多路AT设备，每个LUN对应独立串口/模组\n\n✅ **双通信模式**：支持**主动格式化发送**AT指令+匹配响应，**被动监听**模组主动上报事件（URC），覆盖所有AT通信场景\n\n✅ **配置化指令管理**：通过**枚举+配置表**统一管理AT指令和监听关键字，新增/修改指令无需改动核心逻辑\n\n✅ **鲁棒性保护**：内置指令重发、超时检测、接收缓冲区溢出防护，支持RTOS临界区保护\n\n✅ **格式化指令发送**：支持可变参数的AT指令拼接，无需手动处理`\\r\\n`结束符，简化开发\n\n✅ **易调试**：内置分级日志打印（INFO/WARN/ERROR），通信失败时精准输出错误原因（超时/匹配失败/缓冲区溢出）\n\n✅ **轻量无依赖**：静态内存分配，无动态内存申请，资源占用低，适合小型嵌入式系统\n\n✅ **灵活适配**：支持串口中断/DMA+空闲中断两种接收方式，可根据项目需求灵活选择\n\n## 📂 文件结构\n\n驱动仅包含4个核心文件，结构清晰，易于集成到任意嵌入式工程中：\n\n```C\n\nEmbATlink/\n├── at_driver.c      # 核心驱动层：AT指令收发、响应匹配、被动监听、日志打印等通用逻辑\n├── at_driver.h      # 核心驱动头文件：对外暴露所有API接口\n├── at_port.c        # 硬件抽象层：串口操作、延时、指令表/监听表配置（需用户适配）\n└── at_port.h        # 硬件抽象层头文件：宏定义、指令/监听枚举、硬件层函数声明\n```\n\n## 🏗️ 系统架构\n\n采用**三层架构**实现**硬件无关性**，核心逻辑跨平台复用，移植成本极低，与传统零散AT代码相比，大幅提升可维护性和扩展性：\n\n```C\n\n应用层（模组业务逻辑：Wi-Fi/4G/BLE控制、外设联动）\n    ↕️\n核心驱动层（at_driver.c/h）：通用AT协议逻辑（指令发送、响应匹配、被动监听、超时/重发）\n    ↕️\n硬件抽象层（at_port.c/h）：平台相关硬件操作+配置化管理（串口、延时、Tick、临界区、指令表/监听表）\n```\n\n## 🚀 快速开始\n\n### 步骤1：硬件抽象层适配（仅需修改`at_port.c/h`）\n\n这是唯一需要用户修改的部分，根据自身MCU平台实现硬件相关函数并完成**指令表/监听表配置**，以STM32为例：\n\n1. **修改宏定义**（`at_port.h`）\n\n    - `AT_LUN_MAX`：设置实际使用的AT设备数量（如1路则定义为1）\n\n    - `AT_RECV/SEND_BUFFER_SIZE`：调整收发缓冲区大小，适配不同模组的发送与响应长度\n\n    - 日志宏：默认已开启`printf`打印，无需额外修改（如需关闭，注释即可）\n\n2. **实现基础函数**（`at_port.c`）\n\n    - **先说明LUN含义**：LUN（逻辑单元号）是用于区分多路AT设备的标识，**一个LUN对应一组独立的串口引脚/一个AT模组**；不同LUN的设备通信互不干扰，支持并行工作。\n\n    - `at_port_delay_ms`：对接平台毫秒级延时函数（如`HAL_Delay`）\n\n    - `at_port_get_tick_ms`：对接系统毫秒级时钟（如STM32的`HAL_GetTick`）\n\n    - `at_port_init`：初始化串口接收（中断/DMA），配置对应GPIO\n\n    - `at_port_uart_transmit`：实现串口数据发送\n\n    - （可选）`at_port_enter/exit_critical`：RTOS下实现临界区保护，裸机可留空\n\n**举例**：\n\n```C\n\n/**\n * @brief   AT设备串口数据发送\n * @param   lun: AT设备逻辑单元号\n * @param   buf: 发送数据缓冲区\n * @param   len: 发送数据长度\n * @retval  无\n */\nvoid at_port_uart_transmit(uint8_t lun, const char *buf, uint16_t len)\n{\n    switch (lun)\n    {\n    case 0: // 0号AT设备：系统串口对接Wi-Fi模组\n        HAL_UART_Transmit(\u0026huart1, (uint8_t *)buf, len, 0x100);\n        break;\n    case 1: // 1号AT设备：用户串口对接4G模组\n        HAL_UART_Transmit(\u0026huart2, (uint8_t *)buf, len, 0x100);\n        break;\n    default:\n        break;\n    }\n}\n```\n\n1. **AT指令枚举与配置表定义**（`at_port.h`+`at_port.c`，核心配置）\n\n框架采用**枚举作为索引**+**配置表存储属性**的方式管理AT指令和被动监听关键字，**枚举成员与配置表下标一一对应**，新增/修改指令仅需修改枚举和配置表，无需改动核心驱动逻辑。\n\n#### 3.1 主动发送指令枚举（`at_port.h`）\n\n定义所有需要**主动发送**的AT指令枚举，`AT_CMD_LAST`为指令总数（必须放在最后，用于数组计数，不可删除/修改），`AT_CMD_DEFAULT`为默认占位符：\n\n```C\n\ntypedef enum\n{\n    AT_CMD_DEFAULT = 0x00, /* 默认指令(占位符，不可删除) */\n    AT,                    /* AT基础指令：检测模组在线 */\n    ATE,                   /* ATE指令：配置模组回显 */\n    AT_CMD_LAST,           /* 指令数量(保留放在最后，不可删除) */\n} at_cmd_id_e;\n```\n\n#### 3.2 主动发送指令表（`at_port.c`）\n\n类型为`at_cmd_config_t`的数组，**下标与** **`at_cmd_id_e`** **枚举成员严格对应**，存储每条AT指令的通信属性，结构体成员含义见注释：\n\n```C\n\n/* AT指令表：下标与at_cmd_id_e枚举成员一一对应 */\nconst at_cmd_config_t at_cmd_table[AT_CMD_LAST] = {\n    [AT_CMD_DEFAULT] = {\"AT_CMD_DEFAULT\", NULL, 0, 0, 0},      // 默认指令（占位，属性无意义）\n    [AT] = {\"AT\", \"OK\", 100, 20, 200},                          // 对应枚举AT：基础指令\n    [ATE] = {\"ATE\", NULL, 1, 20, 2000},                         // 对应枚举ATE：回显配置指令\n};\n```\n\n**`at_cmd_config_t`** **结构体成员含义**：\n\n|成员名|类型|含义|\n|---|---|---|\n|`cmd_str`|`const char *`|AT指令基础字符串（如`AT`/`ATE`，可变参数后续格式化拼接）|\n|`expected_rsp`|`const char *`|指令预期响应（如`OK`），NULL表示无需匹配响应，超时后直接返回接收数据|\n|`send_count`|`uint8_t`|指令最大重发次数，超时/匹配失败时自动重发|\n|`check_interval_ms`|`uint16_t`|响应检测间隔，每隔N毫秒检查一次是否收到响应|\n|`recv_timeout_ms`|`uint16_t`|单次接收超时时间，超过N毫秒未收到响应则判定为超时|\n#### 3.3 被动监听关键字枚举（`at_port.h`）\n\n定义所有需要**被动监听**的关键字枚举（模组主动上报/上位机指令），`AT_MONITOR_LAST`为关键字总数（必须放在最后），`AT_MONITOR_DEFAULT`为默认占位符：\n\n```C\n\ntypedef enum\n{\n    AT_MONITOR_DEFAULT = 0x00, /* 默认监控指令(占位符，不可删除) */\n    SYS_LED0_OFF,              /* 监听关键字：LED0关闭指令 */\n    SYS_LED0_ON,               /* 监听关键字：LED0开启指令 */\n    SYS_LED0_TOGGLE,           /* 监听关键字：LED0翻转指令 */\n    AT_MONITOR_LAST,           /* 监听关键字数量(保留放在最后，不可删除) */\n} at_monitor_key_e;\n```\n\n#### 3.4 被动监听关键字表（`at_port.c`）\n\n字符串数组，**下标与** **`at_monitor_key_e`** **枚举成员严格对应**，存储需要监听的关键字，驱动会自动匹配串口接收数据中是否包含该关键字：\n\n```C\n\n/* AT监听指令表：下标与at_monitor_key_e枚举成员一一对应 */\nconst char *at_monitor_key_table[AT_MONITOR_LAST] = {\n    [AT_MONITOR_DEFAULT] = \"AT_MONITOR_DEFAULT\",     // 默认指令（占位，无意义）\n    [SYS_LED0_OFF] = \"AT+LED0=0\",                    // 对应枚举SYS_LED0_OFF：LED0关闭关键字\n    [SYS_LED0_ON] = \"AT+LED0=1\",                     // 对应枚举SYS_LED0_ON：LED0开启关键字\n    [SYS_LED0_TOGGLE] = \"AT+LED0=2\",                 // 对应枚举SYS_LED0_TOGGLE：LED0翻转关键字\n};\n```\n\n1. **串口硬件要求**：根据模组手册配置串口波特率/数据位/校验位/停止位，建议开启串口硬件流控（若模组支持）。\n\n### 步骤2：工程集成\n\n1. 将4个核心文件添加到工程中，新建分组`AT_Driver`管理\n\n2. 在编译器中添加EmbATlink文件夹的头文件路径\n\n3. 重定向`printf`到串口（如STM32重定向`fputc`），并勾选编译器微库（Use MicroLIB）\n\n### 步骤3：驱动初始化\n\n在工程主函数中完成平台初始化后，调用AT驱动初始化函数，示例：\n\n```C\n\n#include \"at_driver.h\"\nint main(void)\n{\n    // 平台初始化（时钟、GPIO、串口、延时等）\n    HAL_Init();\n    SystemClock_Config();\n    MX_GPIO_Init();\n    MX_USART1_UART_Init(); // 对接AT模组的串口初始化\n    \n    // 初始化EmbATlink驱动\n    at_init();\n    \n    while(1)\n    {\n        // 业务逻辑：AT指令发送/被动事件监听\n    }\n}\n```\n\n1. **串口接收回调对接**：将硬件串口的接收回调指向驱动的接收处理函数，以STM32中断接收为例：\n\n```C\n\n#include \"at_driver.h\"\nvoid HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)\n{\n  if (huart-\u003eInstance == USART1)\n  {\n    // 驱动接收核心入口：传递LUN、接收数据、长度\n    at_uart_recv_handler(0, at_rx_data[0], 1);\n    // 重新开启串口中断接收\n    HAL_UART_Receive_IT(\u0026huart1, at_rx_data[0], 1);\n  }\n}\n```\n\n## 📚 核心API\n\n驱动对外暴露**基础初始化函数**和**核心通信函数**，封装了所有AT指令收发的底层细节，直接调用即可满足99%的物联网开发需求。\n\n### 基础初始化函数\n\n```C\n\nvoid at_init(void);                          // 初始化AT驱动，清空缓冲区/初始化硬件\nvoid at_clear_recv_buffer(uint8_t lun);      // 清空指定LUN的接收缓冲区\nchar *at_get_recv_buffer(uint8_t lun);       // 获取指定LUN的接收缓冲区指针\nuint8_t at_get_monitor_match_index(uint8_t lun); // 获取被动监听的事件匹配索引（返回枚举at_monitor_key_e值）\n```\n\n### 核心通信函数\n\n|函数|功能|适用场景|\n|---|---|---|\n|`at_uart_recv_handler`|AT驱动接收核心入口，硬件串口接收后调用|所有场景，必须对接硬件串口回调|\n|`at_cmd_format_send_and_recv`|格式化发送AT指令，自动拼接参数+匹配响应|主动控制模组（如连接Wi-Fi、配置4G）|\n## 💻 使用示例\n\n### 示例1：基础AT指令发送（检测模组在线）\n\n向0号AT设备发送`AT`指令，检测模组是否正常响应`OK`，**函数入参的** **`cmd_id`** **为** **`at_cmd_id_e`** **枚举成员**，与指令表严格对应：\n\n```C\n\n#include \"at_driver.h\"\n#include \u003cstdio.h\u003e\n#define AT_LUN_WIFI 0 // Wi-Fi模组对应0号LUN\nint main(void)\n{\n    // 平台+驱动初始化...\n    at_init();\n    char *recv_buffer = NULL;\n    uint8_t ret;\n    \n    // 发送AT指令，cmd_id为枚举AT，与指令表[AT]对应\n    ret = at_cmd_format_send_and_recv(AT_LUN_WIFI, \u0026recv_buffer, AT, \"\");\n    if (ret == 0)\n    {\n        printf(\"AT指令发送成功，响应：%s\\r\\n\", recv_buffer);\n    }\n    else if (ret == 1)\n    {\n        printf(\"AT指令发送超时\\r\\n\");\n    }\n    else if (ret == 2)\n    {\n        printf(\"AT指令响应匹配失败\\r\\n\");\n    }\n    \n    while(1);\n}\n```\n\n### 示例2：格式化发送带参数的AT指令（配置模组回显）\n\n向0号AT设备发送`ATE1`指令（回显开启），通过可变参数实现指令拼接，**`cmd_id`** **为枚举ATE，与指令表[ATE]对应**：\n\n```C\n\n// 发送ATE1指令，cmd_id为枚举ATE，与指令表[ATE]对应，参数1通过格式化拼接\nret = at_cmd_format_send_and_recv(AT_LUN_WIFI, \u0026recv_buffer, ATE, \"%d\", 1);\nif (ret == 0)\n{\n    printf(\"ATE1配置成功，响应：%s\\r\\n\", recv_buffer);\n}\n```\n\n### 示例3：被动事件监听（模组状态上报/外设控制）\n\n监听上位机/模组的主动上报指令，实现LED灯的远程控制。**`at_get_monitor_match_index`** **返回值为** **`at_monitor_key_e`** **枚举成员**，`switch`的`case`与枚举成员一一对应，最终关联到**监听关键字表**的匹配结果：\n\n1. 驱动自动匹配串口接收数据与`at_monitor_key_table`中的关键字；\n\n2. 匹配成功后，`at_get_monitor_match_index`返回对应的`at_monitor_key_e`枚举值（即`monitor_idx`）；\n\n3. 根据`monitor_idx`（枚举值）执行对应业务逻辑，`switch`的`case`为枚举成员，与**监听枚举+监听表**严格关联。\n\n```C\n\n#include \"at_driver.h\"\n#include \"gpio.h\"\n#define AT_LUN_SYS 0\nint main(void)\n{\n    // 平台+驱动初始化...\n    at_init();\n    HAL_GPIO_WritePin(LED0_GPIO_Port, LED0_Pin, GPIO_PIN_SET); // 初始关闭LED\n    \n    while(1)\n    {\n        // 获取被动监听的事件索引：返回at_monitor_key_e枚举值\n        uint8_t monitor_idx = at_get_monitor_match_index(AT_LUN_SYS);\n        if (monitor_idx != 0xFF) // 匹配到有效事件（0xFF为无匹配）\n        {\n            char *recv_data = at_get_recv_buffer(AT_LUN_SYS);\n            printf(\"监听到事件：%s\\r\\n\", recv_data);\n            // switch的case与at_monitor_key_e枚举成员一一对应，关联监听表的匹配结果\n            switch (monitor_idx)\n            {\n            case SYS_LED0_ON: // 对应枚举SYS_LED0_ON，监听表[AT+LED0=1]\n                HAL_GPIO_WritePin(LED0_GPIO_Port, LED0_Pin, GPIO_PIN_RESET);\n                break;\n            case SYS_LED0_OFF: // 对应枚举SYS_LED0_OFF，监听表[AT+LED0=0]\n                HAL_GPIO_WritePin(LED0_GPIO_Port, LED0_Pin, GPIO_PIN_SET);\n                break;\n            case SYS_LED0_TOGGLE: // 对应枚举SYS_LED0_TOGGLE，监听表[AT+LED0=2]\n                HAL_GPIO_TogglePin(LED0_GPIO_Port, LED0_Pin);\n                break;\n            default:\n                break;\n            }\n            at_clear_recv_buffer(AT_LUN_SYS); // 清空缓冲区，准备下一次监听\n        }\n        HAL_Delay(10);\n    }\n}\n```\n\n**核心关联关系总结**：\n\n```C\n串口接收数据 → 驱动匹配at_monitor_key_table（监听表） → 返回at_monitor_key_e枚举值（monitor_idx） → switch(monitor_idx)执行对应逻辑\n```\n\n## 🚨 故障排除\n\n驱动使用中常见问题及解决方法，按优先级排查：\n\n|问题现象|可能原因|解决方法|\n|---|---|---|\n|AT指令发送超时，返回ret=1|串口硬件未初始化/接线错误|检查串口GPIO配置、模组TX/RX与MCU交叉连接|\n|指令发送成功但响应匹配失败，返回ret=2|预期响应配置错误/模组返回格式不同/发送指令数据过长|检查`at_cmd_table`中`expected_rsp`是否与模组手册一致;增大`AT_SEND_BUFFER_SIZE`|\n|被动监听无响应，monitor_idx始终为0xFF|串口接收回调未对接/缓冲区溢出/枚举-表不匹配|1. 检查`at_uart_recv_handler`是否正确调用；2. 增大`AT_RECV_BUFFER_SIZE`；3. 检查`at_monitor_key_e`枚举与监听表下标是否一一对应|\n|串口乱码/日志打印异常|波特率不匹配/printf未重定向|核对MCU与模组的串口波特率，检查`fputc`重定向和微库勾选|\n|RTOS下通信乱码/指令执行异常|无临界区保护|在`at_port.c`中实现`at_port_enter/exit_critical`，用信号量/关中断保护|\n|缓冲区溢出，日志打印[ERR] RECV BUFFER OVERFLOW|模组响应数据过长|增大`AT_RECV_BUFFER_SIZE`宏定义的数值|\n|指令发送报错/无匹配|枚举与配置表下标不对应|检查`at_cmd_id_e`/`at_monitor_key_e`枚举成员与配置表下标是否严格一致，不可跳过/乱序|\n## 📝 调试方法\n\n驱动内置**分级日志打印**（INFO/WARN/ERROR），无需额外添加调试代码，通信过程全程可追溯，快速定位问题：\n\n1. 日志默认开启：无需修改，确保`printf`重定向成功即可\n\n2. 日志示例：\n\n    - 指令发送成功：`[AT][SUCC] CMD:AT`\n\n    - 指令发送超时重发：`[AT][RETRY][1] CMD:AT, TIME OUT`\n\n    - 响应匹配失败：`[AT][ERR][1] CMD:AT, RECV: ERROR`\n\n    - 缓冲区溢出：`[ERR] RECV BUFFER OVERFLOW (LUN:0)`\n\n日志直接指出**错误类型、指令内容、设备LUN**，大幅降低物联网模组的调试难度。\n\n## 📄 许可证\n\n本项目基于**MIT开源协议**发布，详见 LICENSE 文件。\n\n## 🔗 相关链接\n\n- 详细使用教程：[EmbATlink：高通用性的AT指令驱动框架](https://www.yuque.com/u54102073/rs06a5/lgcn1lumuhqfvcgg?singleDoc#)\n\n- 嵌入式技术交流群：181921938\n\n如果这个项目对你的物联网开发有帮助，请给它一个 ⭐ ！\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzeroonelab%2Fembatlink","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzeroonelab%2Fembatlink","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzeroonelab%2Fembatlink/lists"}