简介:《(完整word版)百度IOT平台——平台使用手册》面向物联网初学者与设备端开发人员,围绕百度IoT云平台的产品创建、设备接入与云端管理流程展开,帮助梳理从开发者中心注册到批量生产的完整链路。压缩包内仅含1个doc文档,约1.35MB,为可编辑的Word版本,便于标注与整理。内容覆盖研发与管理、数据分析、服务与应用三大板块:产品类别、型号与联网方式的设定,CA与Profile文件的烧录,心跳检测的排查思路,数据点定义与测试,批量生产单批次最多10000个Profile,以及OTA固件升级上限10MB、zip格式与静默、强弱提醒模式。数据统计部分给出新增设备、存活、活跃与在网时长的口径;应用侧说明API Key、Secret Key及Android包名、iOS Bundle ID的配置要点。已有384人学习,适合接入调试时对照查阅。
1. 设备"连上了"却不认账,问题往往不在代码
做过物联网 IoT 基础平台接入的人都遇到过这种场面:设备端的 Wi-Fi 图标是绿的,串口日志里 TLS 握手也打出来了,可控制台上那个"心跳检测"按钮点下去,转两圈,弹出来的还是失败。代码没改,配置没动,换一台设备就好了——这种玄学最耗时间。
这份平台使用手册的价值,就在于它把从"新建产品"到"OTA 升级"的七步流程钉死了,每一步该点哪个按钮、该下载什么文件、字段在哪填,写得比散落在各处的接口文档清楚。它适合两类人:一类是第一次把硬件接进公有云 IoT 平台的嵌入式工程师,照着走能少踩一半坑;另一类是已经把设备跑通、准备量产的项目负责人,批量生产和 OTA 那两章才是真正的重点。
2. 产品创建与 CA/Profile:设备上云的第一公里
设备接云这件事,拆开看只有三个动作:平台侧登记身份、设备侧拿到凭证、双方握手成功。手册把这三件事压在了前三个步骤里,但每一步背后都有一层需要你自己决定的选型,选错了后面全得返工。
2.1 产品三要素:类别、型号、联网方式到底怎么填
新建产品时要填的东西不少,真正影响后续流程的只有三个字段。产品类别决定控制台给你推荐哪些模板和服务、默认数据点长什么样;产品型号是批量生产的最小单位,一个型号对应一套 Profile 生成规则;联网方式只作为元数据记录,参与少数统计口径和 OTA 下发策略,不参与鉴权。
| 字段 | 常见误填 | 建议做法 | 影响面 |
|---|---|---|---|
| 产品类别 | 随便选一个最像的 | 按最终交付形态选,不要按当前硬件形态选 | 决定推荐模板、服务列表展示 |
| 产品型号 | 用中文或带空格 | 产品线缩写 + 硬件版本 + 序号,如acv2-01 | 批量生产、OTA 固件绑定 |
| 联网方式 | 全选 | 只选实际出货的通道 | 部分统计口径、下发策略 |
产品型号这一项最容易被轻视。我一般会把它当成硬件 BOM 的一部分来管:PCB 改版、射频模组换料、Flash 分区调整,只要影响固件兼容性,就必须开新型号。理由很直接——OTA 是按型号推的,型号混在一起,等于把不兼容的固件推到别人的设备上。型号命名还要避开中文和空格,有些工具链在拼路径时会把空格吃掉,这属于典型的血泪经验。
另外,产品创建完成之后不要急着往下走。先确认列表里产品的状态是正常、能看到 ProductKey 一类的标识,再去下载凭证。如果产品状态异常,后面下载下来的 Profile 大概率也是无效的,烧进去只会得到一个无限重连的设备。
2.2 CA 与 Profile 的职责边界:一个管加密,一个管身份
这两个文件经常被混为一谈,实际上它们解决的是完全不同的问题。CA 是证书体系的根,负责 TLS 链路上的身份校验和加密,缺了它设备连不上任何 HTTPS/MQTT over TLS 的端口;Profile 是设备自己的身份凭证包,常见做法是里面打包了产品标识、设备名、设备密钥,外加服务器地址和端口。
| 文件 | 承载什么 | 少了会怎样 | 换了会怎样 |
|---|---|---|---|
| CA | 根证书/设备证书链 | TLS 握手失败,日志里反复重连 | 一般不用换,跟环境绑定 |
| Profile | 设备身份三元组 + 接入地址 | 平台侧看不到设备,或认成别的设备 | 等于换了一台设备,历史数据断档 |
手册里写的是"下载 Profile 和 CA,参考设备端开发者手册烧录至设备",没写烧到哪、怎么烧。常见做法是 CA 烧到只读的信任区,Profile 烧到可覆盖的参数区,两者分开,因为前者基本不变、后者在返修和换板时要重写。如果条件允许,Profile 走安全芯片或加密分区,明文存在外部 Flash 里被读出来就等于设备被克隆。
注意:Profile 里通常包含服务器地址。测试环境和生产环境各有一套地址,拿测试环境的 Profile 去连生产环境,现象就是心跳永远检测不到,但设备日志看起来一切正常。这是排查时第一个要确认的点。
还有一个容易被忽略的点:下载下来的 CA 和 Profile 要跟产品、批次对应上。多产品并行开发时,浏览器下载目录里会堆一堆同名文件,靠文件名根本分不清。我一般会在下载后立刻重命名成产品型号_批次_日期的形式再归档,省得三天后回来找不到。
2.3 烧录、联网、心跳:三段式验证顺序不能乱
手册里"检测心跳"这一步写得很轻——点按钮、等弹窗。但它能成功的前提是前面两段都对了。所以验证一定要按顺序来,不能跳步。
第一步,烧录后先做本地自检:设备能不能正常启动、能不能读到 Profile、读到的内容长度对不对。这一步在串口里打几行日志就能确认,比事后在平台上猜要快得多。
第二步,联网阶段看的是链路层。设备连上 AP、拿到 IP、DNS 解析成功、TCP 建连成功、TLS 握手成功,这五件事要分开打日志。很多人把"Wi-Fi 连上了"当成"网络通了",实际上 TLS 握手失败的原因里,证书时间不对、设备 RTC 没校准占了相当比例。
第三步才是平台侧的心跳检测。它的本质是平台从数据面去看这台设备有没有按约定周期上报,不是发个 ping 过去探活。检测成功弹窗出现,说明身份、证书、链路、数据点四件事里最基础的几件都对了。
批量场景下,第三步之前我会先把下载下来的凭证文件过一遍,用脚本生成一份清单。
import os, csv, hashlib PROFILE_DIR = "./profiles" # Profile 下载目录 EXT = ".bin" # 按实际文件后缀改 manifest = [] for name in sorted(os.listdir(PROFILE_DIR)): if not name.lower().endswith(EXT): continue path = os.path.join(PROFILE_DIR, name) with open(path, "rb") as f: digest = hashlib.sha256(f.read()).hexdigest() manifest.append({ "device": os.path.splitext(name)[0], "size": os.path.getsize(path), "sha256_16": digest[:16], # 前 16 位足够做产线比对 "file": name, }) # 同一产品型号下,Profile 体积应当完全一致;不一致说明下载不完整 sizes = {m["size"] for m in manifest} if len(sizes) > 1: print("警告:Profile 体积不一致 ->", sizes) with open("profile_manifest.csv", "w", newline="", encoding="utf-8") as f: w = csv.DictWriter(f, fieldnames=["device", "size", "sha256_16", "file"]) w.writeheader() w.writerows(manifest) print("共校验", len(manifest), "个 Profile")这段脚本做三件事:把文件名还原成设备名建立索引、把文件体积的一致性当作完整性校验、把哈希前 16 位留给产线做烧录后的回读比对。参数就两个,目录和扩展名,按你实际下载下来的格式改。它不解决业务问题,但能在批量下载出现截断、重名、漏下的时候第一时间拦下来——这类问题如果拖到产线上才发现,返工成本是按千台算的。
3. 数据点建模:从"能连上"到"能对话"
心跳通了只代表设备在平台上"活着",离"能用"还差一步:设备上报的字节流,平台得知道哪几个字节是温度、哪几个是电量。数据点就是这个翻译词典,手册里把它放在第四步,实际上它应该是整个项目里最需要提前设计的东西。
3.1 数据点三元组:标识符、名称、数据类型
新建数据点时界面上的字段不多,但每个都有讲究。标识符是代码里真正用的 key,一旦设备烧录了描述文件,改标识符就等于改协议,必须重烧;名称是给人看的,随时能改;数据类型决定序列化方式,改类型同样要重烧。所以标识符和数据类型的组合,应当在第一次测试之前就冻结。
| 数据类型 | 典型用途 | 容易翻车的地方 |
|---|---|---|
| 布尔 | 开关状态、在线标志 | 用 0/1 上报,平台按 bool 解析时可能报类型错 |
| 整型 | 计数值、档位、时间戳 | 32 位有符号存秒级时间戳,2038 年溢出 |
| 浮点 | 温度、湿度、电压 | 精度不统一,设备端保留 2 位、平台端按 6 位展示 |
| 字符串 | 序列号、固件版本 | 长度上限没对齐,超长部分被截断 |
| 枚举 | 模式、故障码 | 后期增删枚举值,APP 端不同步导致显示空白 |
我踩得最深的是浮点精度。设备端为了省 Flash,把温度乘 10 转成整数再上报,平台侧按浮点解析,于是 23.5 变成了 235。这种错误不会报错,只会让看板上出现一条明显不合理的曲线,而且往往要等业务方来问才会被发现。解决办法是在数据点里明确写清楚量纲和缩放系数,别指望下一个人能从字段名猜出来。
枚举类型是另一个隐雷。枚举值本身是好的,可读性比裸数字强,但它的语义分散在三处:设备固件、数据点定义、APP 展示层。任何一处改了,另外两处没跟上,就会显示出空白或者错位。所以枚举我只用在真正稳定的状态机上,业务字段一律走整型加映射表。
3.2 设备描述文件的导出与集成顺序
手册里写"产品创建完数据点后,需导出为设备描述文件,之后将其与 CA 集成,烧入设备"。这句话的顺序很关键,但容易被读成"三个文件一起烧进去就行"。实际上正确的顺序是:数据点先定型,再导出描述文件,然后把描述文件、CA、Profile 三样一起烧录,最后才做数据点测试。
描述文件的结构通常是 JSON,形态大致如下。这里给的是通用形态,实际字段名以设备端开发者手册为准。
{ "product": "acv2-01", "version": "1.0.3", "properties": [ { "id": "temperature", "name": "温度", "type": "float", "mode": "r", "unit": "C" }, { "id": "humidity", "name": "湿度", "type": "float", "mode": "r", "unit": "%RH" }, { "id": "power", "name": "开关", "type": "bool", "mode": "rw" }, { "id": "mode", "name": "工作模式", "type": "enum", "mode": "rw", "values": { "0": "待机", "1": "制冷", "2": "制热" } } ] }mode里的r表示只上报、w表示只下发、rw表示双向可控。这个字段经常被写反,导致下发指令过去设备没反应,或者设备上报上来平台不接收。version不是摆设,它应该跟固件版本一起管理——出了现场问题,第一件事就是确认设备上跑的描述文件版本和平台上配的是不是同一版。
提示:描述文件一旦烧进设备,平台上再改数据点就只影响新烧录的设备,存量设备不会自动同步。所以数据点改动要当成一次固件变更来走流程,别在控制台上顺手改。
3.3 Demo APP 扫码测试的完整闭环
手册里这一步就两句话:点数据点测试、用 Demo APP 扫二维码。听起来很简单,但它是整个接入流程里唯一一次"端到端"验证,值得认真做。
我一般分三轮走。第一轮单点验证:一次只测一个数据点,确认上报值和设备本地显示屏或串口日志一致,别一上来就测全部。第二轮组合验证:所有数据点同时上报,看有没有丢包、有没有互相覆盖。第三轮是边界值:布尔值两边都发一遍,浮点发最大值和最小值,字符串发到长度上限,枚举发一个未定义的值。
第三轮最容易被跳过,也最容易出问题。枚举发未定义值时,APP 端崩不崩、平台侧记不记异常、设备端会不会卡死,这三件事在实验室里测出来是零成本,在现场测出来就是一次故障。测试通过之后再往下走批量生产,这个顺序不能反。
4. 批量生产与 OTA:把一台设备的成功复制成一万台
单台设备跑通,只证明技术路线可行;能不能量产、能不能远程升级,才决定这个方案能不能交付。手册在这两块给了明确的硬约束,读懂这些约束背后的意图比记住数字更重要。
4.1 批次化 Profile 生成:10000 条上限背后是分配问题
批量的逻辑是:选产品型号、新建批次、填批次信息、生成 Profile、下载。手册特别标注了"Profile 数量最多为 10000 个",这个数字不是随便定的,它意味着一个批次对应一张生产工单,超过一万台就要拆批次。
拆批次的时候有个细节:批次号要有递增语义,别用日期做唯一标识。同一天开两条产线是很常见的事,用日期做批次号必然撞车,撞车之后 Profile 和设备就对应不上了。
真正难的是 Profile 和实物设备的映射关系。Profile 文件名通常是设备名,而产线认的是 SN 或者 MAC。这两套命名一旦错位,烧录出来的设备要么互相抢线,要么谁也连不上。我用的方式是产线提供 SN 清单,脚本按设备名做 join,生成烧录映射表。
import os, csv, hashlib BATCH = "B0001" # 批次号 PROFILE_DIR = f"./profiles/{BATCH}" SN_MAP = "./sn_map.csv" # 两列:device_name,sn # 读入设备名 -> SN 的映射 with open(SN_MAP, encoding="utf-8") as f: dev2sn = {r["device_name"]: r["sn"] for r in csv.DictReader(f)} rows = [] for fn in sorted(os.listdir(PROFILE_DIR)): if not fn.lower().endswith(".bin"): continue dev = os.path.splitext(fn)[0] sn = dev2sn.get(dev) if sn is None: # 映射缺失直接中断,不要静默跳过 raise SystemExit(f"缺少 SN 映射: {dev}") with open(os.path.join(PROFILE_DIR, fn), "rb") as f: h = hashlib.sha256(f.read()).hexdigest()[:16] rows.append({"sn": sn, "device": dev, "batch": BATCH, "sha256_16": h, "file": fn}) with open(f"burn_map_{BATCH}.csv", "w", newline="", encoding="utf-8") as f: w = csv.DictWriter(f, fieldnames=["sn", "device", "batch", "sha256_16", "file"]) w.writeheader() w.writerows(rows) print("本批次生成烧录映射", len(rows), "条")关键在"映射缺失直接中断"这一行。批量脚本最忌讳的是遇到异常数据默默跳过,产出看起来正常、实际少了几十台,等到上线激活率不对才发现。参数上,BATCH和目录要保持一致,SN_MAP必须是产线源头给的数据,不要手工维护。哈希值留在表里,产线烧录后回读一次做比对,这是防止"烧错片"的最后一道闸。
4.2 OTA 固件的 10MB 与 zip:格式约束比大小更致命
固件上传的硬约束是最大 10MB、格式为 zip。10MB 对现在的 MCU 固件来说其实挺宽裕,真正让人翻车的是 zip 的打包方式。
最常见的失败是打成"套娃包":在父目录里选中文件夹右键压缩,解出来是firmware/xxx.bin,平台解包后找不到根目录下的固件文件,直接判格式错误。第二种是 macOS 打包带进来的__MACOSX和.DS_Store,Windows 侧解出来一堆垃圾文件,同样报错。
cd firmware_build # 先进到固件产出的根目录 rm -f ../ota_acv2-01_1.2.3.zip # -X 去掉额外的文件属性,-x 排除隐藏文件和系统垃圾 zip -r -X ../ota_acv2-01_1.2.3.zip . -x ".*" -x "__MACOSX/*" unzip -l ../ota_acv2-01_1.2.3.zip # 上传前必须看一眼目录结构cd进去再打包是关键,保证 zip 的根就是固件根。unzip -l这步别省,两秒钟的事,能省掉一次上传失败后的重新走流程。文件名里带上型号和版本号,OTA 记录里对得上,事后追问题方便。
另外,10MB 这个上限要留余量。固件 9.8MB 的时候,下一次加个日志模块就超了。我的习惯是把 8MB 当作实际红线,超过就开始拆分固件或者裁剪功能,而不是等撞墙。
4.3 四种通知方式怎么选:静默、强提醒、弱提醒、被动提醒
手册把升级规则分成四种:静默是直接升级、无提醒、无需用户干预;强提醒、弱提醒、被动提醒则是推送到 APP 端,由用户在 APP 里操作。这四种不是随便挑的,它跟设备形态强绑定。
| 模式 | 适合的设备 | 风险 |
|---|---|---|
| 静默 | 无屏、无人值守、传感器类 | 升级中被断电可能变砖,必须有回滚 |
| 强提醒 | 有屏、用户每天使用 | 用户点"稍后"会一直拖着不升 |
| 弱提醒 | 有屏但使用频次低 | 提醒容易被忽略,长期停留在旧版本 |
| 被动提醒 | 用户主动进设置页才看到 | 覆盖率最低,适合小版本 |
无屏设备选静默是合理的,但前提是你做了双分区和回滚。单分区静默升级,一旦新固件启动失败,设备就彻底失联,只能派人上门。这个后悔药必须提前准备,不是出事之后再补。
有屏设备我更倾向弱提醒加一个"升级后才生效"的策略:用户不点,功能照常但新特性不可用,慢慢把版本推上去。强提醒点多了会被投诉,尤其对消费级产品。
4.4 版本号规划与回滚:OTA 的后悔药要提前熬
固件版本号建议走三段式:主版本.次版本.修订号。主版本改通信协议或描述文件结构,次版本加功能,修订号修 bug。这个规则的价值在于,它能让你一眼看出"这次升级会不会导致设备必须重新烧录描述文件"——会,就升主版本。
回滚的策略是:任何一个版本上线,平台上始终保留上一个可用版本的固件包。发现异常先停推、再回滚,不要在新版本上打补丁式地连发三个修订版,现场会乱成一锅粥。
注意:平台只负责把固件推下去,不负责判断升级是否成功。升级结果的确认要靠设备端在新固件启动后上报一次版本号数据点,平台侧用"固件版本分布"来看覆盖率。
5. 常见问题排查:五条踩坑记录与定位路径
前面四步走完,理论上设备已经能跑通了。但实际项目里真正消耗时间的,是那些"看起来都对、就是不工作"的状态。下面这五条是我在不同项目里反复遇到的,按现象、原因、解决拆开写。
5.1 设备侧:心跳检测一直失败,但串口日志显示已连上
现象:设备串口里能看到 TCP 建连成功、TLS 握手完成,甚至能看到上报的数据包发出去了,但平台上点心跳检测,转两圈还是失败。
原因通常有两个。一是 Profile 里的服务器地址跟当前环境不匹配,设备连的是测试环境,你在生产控制台上查。二是设备名重复——同一份 Profile 被烧到了两台设备上,后上线的那台把前一台顶掉,两台互相踢,平台上看到的是连接时断时续。
解决:先在设备端把 Profile 里的接入地址打印出来,跟控制台当前环境核对;再查平台上这台设备名的连接记录,如果出现频繁上下线,基本可以断定是 Profile 重复。批量场景下,用 4.1 里的映射脚本先跑一遍,重复设备名在脚本里就能拦住。
5.2 设备侧:数据点测试扫码后,APP 一直没有数据
现象:心跳检测通过,设备也在正常上报,但用 Demo APP 扫码进入数据点测试后,页面上一个值都没有。
原因几乎都是描述文件版本不一致。改了数据点之后没有重新导出描述文件、没有重新烧录,设备还在按旧的协议上报,平台按新的定义解析,字段对不上就整包丢弃。另一种情况是导出后只烧了描述文件,忘了重新集成 CA,导致签名校验不通过。
解决:把数据点定义、描述文件版本、固件版本三者对齐,重新导出、重新烧录、重新测试。这类问题很难从现象上直接看出来,所以我在项目里强制要求描述文件版本号跟着固件版本号一起展示在设备信息里,一眼就能比对。
5.3 设备侧:批量生产后,一部分设备无法激活
现象:同一个批次两百台设备,一百八十台正常,二十台怎么都激活不了。
原因有两种。一是批次 Profile 下载不完整,文件被截断,烧进去是坏数据;二是产线烧录时顺序错位,同一份 Profile 烧到了两个片子,或者 Profile 和 SN 的对应关系整个错开。
解决:先跑 2.3 里的清单脚本,看文件体积是否一致、数量对不对;再跑 4.1 的映射脚本,确认 SN 和设备名一一对应。如果还定位不到,就取一台异常设备回读 Profile 的哈希,跟映射表里的哈希比对,能直接判断是"烧错了"还是"文件本身坏了"。
5.4 平台侧:OTA 上传固件报格式错误
现象:zip 包本地解压完全正常,大小也没超,上传就是报格式错误。
原因基本锁定在包结构。要么是压缩时多套了一层目录,要么是带了系统垃圾文件,要么是扩展名写成.ZIP大写导致校验失败。
解决:按 4.2 的命令重打一次包,cd到固件目录内部再压缩,用unzip -l确认根目录下直接就是固件文件。上传前顺手检查一下文件大小写和扩展名。
5.5 统计口径:活跃设备数远小于存活设备数
现象:数据统计页面上,设备存活数有八百多,活跃设备数只有一百出头,业务方拿着这个数字来问是不是设备大面积故障。
原因不是故障,是口径。手册里的定义很清楚:存活是"有数据上报",心跳也算;活跃是"有非心跳数据上报",只发心跳不算。大量设备处于只保活、没人操作的状态,这个差值天然存在。
解决:做设备健康度看板的时候,用存活率看在线情况,用活跃率看使用情况,两者不要混。想判断"设备是不是真的坏了",看新增设备和在网时长分布更准。这里最容易犯的错是拿活跃率当在线率汇报,数字一低就被当成事故。
6. 应用侧联调与上线自检:把手册走成一张可勾选的清单
设备通了、固件推了,最后一步是 APP 侧。手册里这块写得很简略:创建应用、拿到 API Key 和 Secret Key、按平台填包名或 Bundle ID。但正是这几个字段,在上线前最容易出问题。
6.1 AK/SK 与平台差异:别把 Secret Key 塞进客户端
创建应用之后能拿到两个东西:API Key 和 Secret Key。前者的定位是公开标识,可以放在客户端;后者的定位是密钥,只能放在你自己的服务端。把 Secret Key 打进 APK 或 IPA,等于把整个应用的权限公开,反编译一次就能拿到。
平台差异这块,Android 要填包名和应用签名,iOS 要填 Bundle ID。有两个坑值得单独说。Android 的签名一定要用 release 签名,不要用 debug 签名,因为两者指纹完全不同,用 debug 签名联调通过、换成 release 就鉴权失败的情况太常见了。iOS 的 Bundle ID 区分大小写,控制台里填com.example.app、工程里配com.example.App,看起来一样,实际不匹配。
6.2 上线前的一张自检表
手册里提到的服务列表和服务管理,主要用来查看基础数据和跳转文档,联调阶段不需要动。真正需要逐项确认的,是下面这张表。
| 检查项 | 通过标准 |
|---|---|
| 产品型号与固件 | 型号与固件版本严格对应,无跨型号混推 |
| CA 与 Profile | 来源批次可追溯,设备侧回读哈希与映射表一致 |
| 数据点定义 | 标识符和数据类型已冻结,描述文件版本随固件记录 |
| 数据点测试 | 单点、组合、边界值三轮全部通过 |
| 批量映射 | 每个 SN 都能在映射表里找到唯一 Profile |
| OTA 固件包 | 根目录结构正确,体积低于实际上限,保留上一版本 |
| 通知方式 | 按设备形态选定,无屏设备已具备回滚能力 |
| 应用配置 | release 签名或 Bundle ID 与后台完全一致 |
| 统计口径 | 存活率与活跃率分开解读,有明确定义文档 |
这张表不是走形式用的。我现在的习惯是,任何一次设备接入交付,都强制从上到下走一遍,哪怕项目再小、哪怕这套流程已经跑过十次。因为翻车的往往不是最难的那一步,而是"上次好好的,这次应该也没问题"的那一步——一个批次号写错、一份 Profile 烧重、一个 debug 签名混进 release 包,都足够让上线推迟一周。希望这份拆解能帮你在第一次接入时少绕几个弯。
本文还有配套的精品资源,点击获取