贺简云IoT 是一站式物联网接入平台:让任意支持 HTTP / 网络的设备、程序或电路板「连上来」,把采集到的数据「存起来、看得见」,还能按条件「自动联动」,最后把数据做成网页「放出去」给最终用户使用。
层级能力一句话说明
第一层设备接入 API设备 / 程序用 device_id + token 即可接入:上报数据、接收指令,无需网页登录。
第二层规则引擎数据到达后按条件自动做动作(下发指令 / 请求外部网址 / 通知等),无需写业务代码。
第三层可视化应用工作台拖拽组件绑定设备属性,一键发布为免登录的公开网页,别人打开链接就能看数据、点按钮。

本文档所有示例统一使用平台地址:https://www.hjyiot.cn/api.php。遇到任何问题,可通过文末官方客服 QQ 联系我们。

请选择适合你的版本

🟢 零基础版没接触过物联网、不会写代码也没关系。从头讲起,跟着一步步点就能完成:注册 → 建设备 → 做页面。
🔵 新手版会一点编程、用过命令行(curl)。直接看核心概念 + 三个接口,最快把设备数据接上来。
⚫ 老手版有嵌入式 / 后端经验。只要协议细节:接口规格、鉴权、队列语义、限流、错误码、子接口。

三版内容相互独立,可随时切换;页面最下方附官方客服联系方式

📦 开发者 SDK · 下载即用

平台官方提供两套 SDK,把本文档的接入上报 / 指令 / 云盘接口封装成可直接调用的函数,新设备最快 10 分钟完成接入。均为轻量开源实现、无第三方依赖,可直接阅读源码对照下方协议章节。

SDK适用场景包含内容下载
HjyIot
ESP32 Arduino 库
ESP32 开发板(板载 WiFi),Arduino IDE / PlatformIO 均可 HjyIot.h/.cpp + 官方库描述 library.properties + 示例 device_basic(接入上报)、cloud_disk(云盘写入)、ota_update(OTA 固件下载) 下载 ZIP
hjyiot
Python 3 模块
树莓派 / PC / 网关 / 服务端脚本,仅用 Python 标准库 hjyiot.py + 示例 device_basic.py(接入上报)、cloud_disk.py(云盘写入)、ota_download.py(OTA 固件下载) 下载 ZIP

📖 SDK 使用说明(目录结构 / 函数速查 / 示例对照):SDK使用说明.md;也可直接浏览散文件目录 assets/docs/sdk/

💡 快速开始:Arduino 用户把 ZIP 解压进 libraries/(库名 HjyIot),菜单「文件 → 示例 → HjyIot」即见三个 demo;Python 用户把 hjyiot.py 放进项目目录后 from hjyiot import HjyIot 即可。接口协议细节对照下方 2.1 鉴权2.10 云盘接口2.11 OTA 固件下载;示例与接口一对一关系见老手版开头说明。

📦 平台功能一览(每个功能是做什么的)

登录平台后,左侧菜单从上到下依次是这些功能模块(不同角色可见项略有差异):

功能模块面向谁能做什么典型场景
工作台总览所有登录用户一页看清全局:设备总数、在线设备数、应用数(已发布几个)、启用规则数;提供快速开始向导;展示我的租户信息与平台动态。每天打开先看设备有没有掉线、整体运行是否正常。
设备管理所有登录用户创建设备、查看设备在线状态;查看属性快照(设备最近上报的数据汇总);查看设备日志(心跳、上报、指令等历史);手动下发指令;查看与重置设备令牌 token。新设备上线登记;排查某台设备为什么没数据;远程手动开关一次设备。
应用工作台所有登录用户可视化搭网页:7 种组件(文本、指标大数字、仪表盘、折线图、开关、按钮、分隔线),拖进画布、绑定设备属性即可。一键「发布」生成免登录公开链接,可分发给任何人;可「下架」停止访问、可「重置密钥」让旧链接立即失效。给客户做一个大屏展示温湿度;给现场工人做一个手机能点的控制面板。
规则引擎所有登录用户图形化配置自动化:4 种触发器(设备上报 / 状态变化 / 定时 / Webhook)+ 条件 + 5 种动作(下发指令 / 触发链式规则 / 请求外部 HTTP / 站内通知 / 修改属性),并可查看每条规则的历史执行日志。温度超过 30 度自动开风扇;设备掉线自动通知;每天 8 点自动巡检。
接入文档(本页)所有人分版本说明如何把设备 / 程序接入平台。首次接入先读这里。
平台管理平台管理员管理成员账号(创建 / 启停 / 重置密码)、管理租户(启停)、维护系统设置(平台名称、客服联系方式、备案信息等)。给同事开账号;改平台显示名称与客服信息。
设备云盘所有登录用户每个租户 10MB 共享小空间(仅 txt / jpg):建目录、新建 / 编辑 txt、浏览与删除;设备经三个只读接口读取、经属性上报包里的 fs 指令写入文本。设备写运行日志与配置文本,当作轻量数据交换区。
OTA 固件升级所有登录用户设备固件的在线升级闭环:上传 .bin 固件(推荐,免编译)或 .ino 源码 → 平台审查 / 编译 → 推送设备;设备侧用 ota_download 下载固件并校验。固件与云盘共享 10MB 配额给已部署的设备远程升级功能,不用到现场接线。
账号与安全能力所有用户注册即自动创建独立开发者空间(租户);支持修改密码;设备接入使用「设备 ID + 令牌」双重凭据,与网页登录账号相互隔离;公开页只暴露你主动绑定并发布的数据。设备令牌泄露只影响单台设备,重置即可,不影响后台账号。

平台对外开放能力速览:HTTP 设备接入(心跳 / 属性上报 / 指令拉取)、设备 OTA 固件下载ota_download,见老手版 2.11)、设备云盘接口(只读三接口 disk_stats / disk_list / disk_read,云盘内容维护随属性上报携带 fs 指令完成,见下方老手版 2.10 云盘接口)、免登录公开应用页(查看 + 点击操作)、公开 JSON 子接口(供自研前端 / 大屏对接)、Webhook 外部联动(第三方系统触发规则)。详见下方对应版本与协议章节。

💡 我的设备 / 程序怎么对接云盘?看下方「设备对接云盘 · 接口速查」,老手版 2.10 云盘接口 还有完整协议与限制说明。要点:云盘不开放整文件上传 / 下载;网页端左侧菜单「云盘」可建目录、建 txt、浏览与删除;设备新增或维护文本统一走属性上报包内的 fs 指令(写入须显式提供目标文件路径),读取走三个只读接口。首次对接请先按零基础版流程创建好设备并拿到 token。

📡 设备对接云盘 · 接口速查

同一租户下的所有设备共享一个云盘(默认 10MB,仅支持 txt / jpg)。⚠️ 这 10MB 是账户级共享配额,与 OTA 固件(见下方「设备 OTA 升级 · 接口速查」)合计计算,固件需在「OTA 升级」页删除任务才能释放。设备接入凭据与设备接口完全一致:HTTP Basic(user=设备ID,pass=token)或 X-Device-ID + X-Device-Token。以下示例统一走平台 API:https://www.hjyiot.cn/api.php

动作方法 / 请求返回要点
查看空间GET https://www.hjyiot.cn/api.php?action=disk_statslimit / used / free / percent / read_only / quota_hit / disabled / file_types;写满、封禁时 read_only=1,封禁态拒绝访问并返回原因
列目录GET https://www.hjyiot.cn/api.php?action=disk_list&path=<目录,可省略>rel / items[](条目含 name、type、ext、size、modified、frozen)、配额与只读状态
读取文件GET https://www.hjyiot.cn/api.php?action=disk_read&path=<文件完整路径>txt 返回 content(原文);jpg 返回 data(base64)
写入 / 覆盖文本POST https://www.hjyiot.cn/api.php?action=report,Body={"props":{},"fs":[{"op":"write","path":"<txt路径>","content":"<文本>","mode":"append|overwrite","create":true|false}]}fs[] 逐项返回 op/path/ok/bytes/created/mode;追加默认 append;目录或文件不存在时默认报错,显式 create:true 才自动创建
删除文件POST https://www.hjyiot.cn/api.php?action=report,Body={"props":{},"fs":[{"op":"delete","path":"<文件路径>"}]}fs[] 返回 op/path/ok;仅可删除文件,目录删除请由平台网页端处理
删除文本片段POST https://www.hjyiot.cn/api.php?action=report,Body={"props":{},"fs":[{"op":"delete_content","path":"<txt路径>","needle":"<要删除的片段>","all":true|false}]}fs[] 返回 op/path/ok/removed/bytesall=false(默认)仅删首个匹配,all=true 删全部匹配

写入示例(Linux / macOS / Windows PowerShell 通用,用 curl;先建目录可省略 create,未建目录需带 "create":true):
curl -u 设备ID:token -H "Content-Type: application/json" -X POST "https://www.hjyiot.cn/api.php?action=report" --data '{"props":{},"fs":[{"op":"write","path":"logs/2026-09-08.txt","content":"温度 37.5℃\n","create":true}]}'
读取示例:curl -u 设备ID:token "https://www.hjyiot.cn/api.php?action=disk_read&path=logs/2026-09-08.txt"

⚠️ 云盘不接受整文件上传 / 下载:所有文本写入 / 覆盖 / 内容删除 / 文件删除都通过属性上报包内的 fs 指令完成(见上表 3 条与老手版 2.10 细则);jpg 文件只能经 disk_read 读取内容,其内容写入由平台按业务策略维护,设备无法新增 jpg。

📶 设备 OTA 升级 · 接口速查

平台提供设备固件的在线升级闭环:上传固件 / 源码 → 审查 / 编译 → 推送设备 → 设备下载并校验。上传与推送在网页端左侧菜单「OTA 升级」完成;设备侧只做一件事:收到 OTA 指令后调用 ota_download 下载固件二进制。固件与云盘共享账户 10MB 配额disk_stats.used 已含固件占用)。

动作方法 / 请求返回要点
下载固件GET https://www.hjyiot.cn/api.php?action=ota_download&job_id=<任务ID>(POST 亦可,body {"job_id":"..."}成功返回二进制流application/octet-stream不是 JSON),响应头 X-OTA-Version / X-OTA-SHA256 / X-OTA-Size / X-OTA-Job;失败才返回 JSON:1002 功能停用 / 云盘封禁 / 固件冻结,1003 任务不存在,1004 缺 job_id / 未就绪 / 窗口过期,1006 固件文件缺失
拉取 OTA 指令GET https://www.hjyiot.cn/api.php?action=command推送后设备会拉到 type=ota 指令,其 payload = {version, job_id, size, sha256, ts}

下载示例(-OJ 按响应头文件名落盘;下完务必比对 X-OTA-SHA256):
curl -u 设备ID:token -OJ "https://www.hjyiot.cn/api.php?action=ota_download&job_id=<任务ID>"

⚠️ 三条硬规则:① 下载窗口 24 小时(自最近一次推送起算),过期需在网页端重新推送;② 任务删除有限制——仅「排队中 / 编译中」不可删,其余状态可删,删除会一并清理 .ino / .bin 并释放配额;③ 固件只能在「OTA 升级」页删除任务释放,云盘侧无法删除。完整状态机、审计口径与 SDK 用法见老手版 2.11 OTA 固件下载

💬 官方客服

官方客服 QQ:3182076356 (接入咨询 / 报错排查 / 功能建议 / 商务合作,请备注「平台接入」)

建议先按本文档自测:零基础版每步都可在网页内完成;出现看不懂的返回码时,把「设备 ID + 页面 + 返回 JSON」一起发给客服,能更快定位。

🏠 关于我们

创始人:散人
官方 QQ:3182076356
平台上线:2026-09-06 已稳定运行 18

贺简云IoT 是一站式轻量物联网平台:设备接入、数据可视化、自动化联动、免登录公开页与租户云盘开箱即用。产品由创始人散人独立开发并持续运营,任何建议、反馈与合作,欢迎通过上方 QQ 联系。

🟢 零基础版 · 跟着做就能完成接入

如果你:没接触过物联网、看不懂代码、手里可能还没有开发板——就读这一版。它不要求你会编程,只要求你能点鼠标、会复制粘贴。

读完这一版你能做到:① 注册平台并创建你的第一台「设备」;② 让这台设备产生第一条真实数据并在网页上看到它;③ 把数据做成一个网页链接,发给任何人(对方不用登录也能看);④ 明白平台怎么帮你自动干活。

路线图(约 15~30 分钟):注册账号 → 认识几个词 → 创建设备 → 把数据送上来(复制粘贴命令即可)→ 回平台看数据 → 做一个公开网页 → 了解自动联动 → 卡住就看 FAQ。

0.1 准备什么

  1. 一台能上网的电脑(或手机浏览器,但本版步骤用电脑最方便,需要能打开「终端 / PowerShell」)。
  2. 一个邮箱,用于注册账号。
  3. 可选的硬件:如果你有 ESP32 / 树莓派 / 其他开发板或电脑程序,后面可以把它们接进来;暂时没有也没关系,前几步用平台自带的「假设备数据」就能学会。

0.2 先认识 7 个词(用生活比喻,先混个脸熟)

名词它是什么生活比喻在哪看
租户 / 开发者空间平台为你单独划分的工作区,你的设备和数据都在里面,别人看不到。你在平台上的「独立办公室」。注册后自动创建;工作台总览可看租户 ID。
设备 ID(device_id)你给设备起的「名字 / 工号」,用来区分每一台设备。员工工牌上的编号。创建时自己填写,之后在设备列表可见。
令牌(token)设备接入平台的「密码」,只有设备自己知道。办公室门禁密码。创建后由平台生成,设备详情可查看 / 重置。
属性(props)设备上报的数据,比如温度、湿度、开关状态。平台会自动汇总成这台设备的「属性快照」。体检报告上的各项指标。设备管理 → 设备详情 → 属性快照。
指令(command)平台想叫设备做的事,例如「打开继电器」。指令先存放在平台队列,设备主动来取并执行。前台给你留的「待办便签」,你路过时取走处理。设备管理 → 下发指令;规则引擎也可自动下发。
云盘(共享存储)每个租户自带的 10MB 共享小空间(只放 txt / jpg)。网页端「云盘」菜单可建文件夹、新建 txt、浏览 / 删除;你的设备也能往里写文本日志、读回数据(见顶部「设备对接云盘 · 接口速查」)。这 10MB 与 OTA 固件共享。公司的公共储物柜:便签和照片往里放,设备也能存取。左侧菜单「云盘」。
应用 / 公开页把设备数据做成网页给别人看 / 操作,对方不用注册登录。贴在门口的大屏展示牌。应用工作台 → 新建应用 → 发布。
OTA 固件升级给设备里的程序「远程换新版本」:在网页端上传固件或源码,平台审查 / 编译后推送给设备,设备自己下载并重启生效(见顶部「设备 OTA 升级 · 接口速查」)。给手机远程升级系统版本。左侧菜单「OTA 升级」。

现在不用背下来,先有个印象;后面每一步都会再次遇到它们。

0.3 第一步:注册账号并登录

  1. 打开平台官网(访问你收到的平台地址),点击右上角「注册」。
  2. 按提示填写账号信息并完成注册。成功后平台会自动为你创建独立开发者空间(租户),不需要你手动开通
  3. 回到登录页,用刚注册的账号登录。登录后会进入「工作台总览」,你会在页面右侧「我的租户」里看到租户 ID——先不用管它,后面设备接入不需要手动填。
如果注册后收不到邮件 / 短信验证码,多半是被拦截或延迟,先等 1~2 分钟并检查垃圾箱;仍不行就把注册账号发给我们客服处理。

0.4 第二步:创建你的第一台「设备」

这里说的「设备」不一定是真实硬件,它只是平台里的一个身份档案。真实硬件 / 程序之后用这个身份来上报数据。

  1. 左侧菜单点「设备管理」,点右上角「+ 创建设备」。
  2. 填写:
    • 设备标识(device_id):建议用英文、数字、中划线或下划线,例如 demo-sensor-01。它相当于设备工号,建议全平台内保持唯一,容易记。
    • 设备名称:给人类看的中文名,例如「客厅温湿度传感器」,可以随时改。
  3. 点「创建」。保存后,平台会自动生成一个令牌(token),一长串随机字符(例如 32 位)。
  4. 马上复制并保存好这个 token:它只在创建时完整展示一次,之后可以在设备详情里查看或重置。它相当于设备密码,不要发给无关的人。
「设备 ID」和「令牌」的区别:ID 是公开的工号,令牌是私密的密码。别人即使知道你的设备 ID,没有令牌也动不了你的设备。

0.5 第三步:把第一条数据送上来(不用懂原理,复制粘贴即可)

现在让这台设备产生「第一条真实数据」。需要用到电脑自带的命令行工具:Windows 用 PowerShell,Mac 用「终端」。全程只需要复制粘贴下面两段,然后按回车

① 在设备管理页找到你的 device_id 和 token

进入「设备管理 → 设备详情」,把 device_idtoken 两串字符复制到下面命令的对应位置(下面以 demo-sensor-01 为例)。

② 先发一次「心跳」,让平台知道设备上线了

Windows(打开 PowerShell),把下面整段复制进去回车:

curl -u demo-sensor-01:你的token -X POST "https://www.hjyiot.cn/api.php?action=heartbeat"

Mac(打开「终端」),复制同样内容回车即可。

你会看到类似这样的返回:

{ "code":0, "msg":"成功", "data":{ "online":1, "server_ts":1728000000, "last_seen":1728000000, "rate":null } }

只要看到 "code":0 就是成功;online:1 表示平台已把设备标记为在线。看不懂没关系,记住「code:0 = 成功」即可。

③ 上报一条数据(属性)

Windows(PowerShell)

curl -u demo-sensor-01:你的token -X POST -H "Content-Type: application/json" -d "{\"ts\":1728000000,\"props\":{\"temperature\":26.5,\"humidity\":58}}" "https://www.hjyiot.cn/api.php?action=report"

Mac(终端)

curl -u demo-sensor-01:你的token -X POST -H 'Content-Type: application/json' -d '{"ts":1728000000,"props":{"temperature":26.5,"humidity":58}}' "https://www.hjyiot.cn/api.php?action=report"

这段的意思是:把「温度 26.5、湿度 58」这两个属性上报给平台。返回 "code":0 即成功。

Windows 的 PowerShell 对引号要求严格,请整段复制、不要手动改动引号;如果提示错误,把返回内容复制给客服即可。Mac / Linux 用单引号版。

0.6 第四步:回平台确认数据真的到了

  1. 回到「设备管理」,刷新列表:这台设备的在线状态应该已变成「在线」。
  2. 点进「设备详情」,找到「属性快照」:应能看到刚才上报的 temperature: 26.5humidity: 58
  3. 再看「设备日志」:刚才的心跳和上报会记录在这里,每条都有时间戳,方便以后排查问题。

到这里,你已完成一次完整的「设备 → 平台」数据链路。把上面的 demo-sensor-01 和命令替换成你的真实 device_id / token,以后每次想测试就重复 0.5 的命令即可。

0.7 第五步:做一个网页,把数据放出去给别人看

这一步不需要写任何代码,全部用鼠标完成:

  1. 左侧菜单点「应用工作台」,点「+ 新建应用」,填个名字(如「我的第一个大屏」),进入编辑器。
  2. 从左侧组件区拖一个「指标(大数字)」到画布,再拖一个「仪表盘」,还可以拖一个「文本」当标题。
  3. 点中某个组件,右侧面板选择要绑定的设备(就是刚才那台)和属性(temperature 或 humidity)。
  4. 点「保存」,回到应用列表,点「发布」。平台会生成一个 公开链接(形如 http://www.hjyiot.cn/app.php?app=应用ID&k=一串密钥)。
  5. 把这个链接发给任何人:对方不用注册、不用登录,打开就能看到实时数据。
  6. 不想给别人看了?在应用列表点「下架」,链接立即失效;也可以点「重置密钥」,让旧链接立刻作废并生成新链接。
公开链接等于把数据「公开展示」,请只绑定你愿意公开的属性;想保密的数据不要放进这个页面。

0.8 第六步:让平台自动干活(规则引擎)

规则引擎用大白话说就是:「如果发生了某件事,就自动做某个动作」。你不需要写程序,在网页里下拉选择就行。

例子如果(触发)就自动(动作)
温度过高自动开风扇设备上报的温度 > 30向风扇设备下发指令「打开」
设备掉线提醒某设备由在线变为离线站内通知我
定时巡检每天早上 8:00下发一条指令让设备上报一次数据
外部系统联动第三方系统调用我规则的专属网址(Webhook)请求一个外部接口 / 下发指令

现在不用急着配置,先到「规则引擎」页点「新建规则」看一眼界面即可;等你熟悉了数据链路,再回来配置第一条自动化。每条规则跑过之后,都可在「执行日志」里看到它有没有被触发、动作成没成功。

0.9 常见问题(FAQ)

问题解答
token 忘了 / 泄露了怎么办?设备详情里点「重置令牌」,新 token 会立刻生效,旧 token 立即作废。改完记得同步更新你设备端配置。
设备一直显示「离线」?平台只有在设备最近主动联系过时才算在线。检查设备是否在按节奏发心跳(每 30~60 秒一次比较常见);刚上报完 30 秒内看列表最准。
上报成功但页面没数据?多半是属性名不一致:比如设备上报的是 temperature,而页面组件绑定的是 Temperature(大小写也算不同名字)。让两边逐字一致即可。
我没有开发板,能继续学吗?完全可以。用 0.5 的命令行模拟设备即可;想练「收指令」可以看新手 / 老手版的模拟示例。
Windows 粘贴命令报错?PowerShell 只接受整段原样粘贴,注意双引号不要被输入法改成中文引号;不行就换 Mac / Linux 试,或直接联系客服。
公开链接打不开 / 提示失效?链接可能被重置或应用被下架。去「应用工作台」重新发布或重新复制最新链接。
「下发指令」后设备没反应?指令是「设备主动来取」的:确认设备端在按节奏调用指令拉取接口(见新手 / 老手版),并确认设备执行后把结果回传。
设备固件怎么远程升级?左侧菜单「OTA 升级」上传 .bin 固件(免编译、免费、即传即用,推荐)或 .ino 源码,通过后点「推送」;设备收到 type=ota 指令后调用 ota_download 下载固件并校验 SHA-256,重启即生效。注意:下载窗口 24 小时内有效,过期要重新推送;固件与云盘共享 10MB 配额,且只能在「OTA 升级」页删除任务释放。
云盘是什么?设备怎么往云盘写东西?每个租户自带 10MB 共享云盘(仅 txt / jpg)。网页端「云盘」菜单可建文件夹 / 新建 txt / 删除;设备经三个只读接口读取、经属性上报包里的 fs 指令写入文本。云盘不开放整文件上传 / 下载,详见页面顶部「设备对接云盘 · 接口速查」与老手版 2.10。

0.10 下一步学什么

  • 想把真实硬件 / 程序接上来(ESP32、电脑脚本等)→ 看 新手版(讲原理更细)与 老手版(协议细节)。
  • 想把页面做得更丰富(开关、按钮、折线图)→ 回到「应用工作台」多试几种组件。
  • 卡在任何一步 → 返回顶部找官方客服 QQ,附上你的截图与返回内容。

🔵 新手版 · 会一点编程,最快把设备接上来

如果你:会写一点代码、用过命令行(curl),但第一次接触这个平台——就读这一版。它默认你懂「请求 / 响应、JSON、HTTP」这些基本概念,只讲平台特有的约定。

读完这一版你能做到:用 3 个 HTTP 接口把任意设备接入平台,完成「心跳保活 → 属性上报 → 指令拉取与执行回传」的完整闭环,并知道如何接入规则引擎和可视化应用。

最快的接入路径:注册 → 设备管理创建设备(拿 device_id + token)→ 用下面 curl 样例跑通心跳与上报 → 平台设备详情确认数据 → 接入你自己的程序循环。全程约 10 分钟。

1.1 平台特有概念(与普通 Web API 不同的地方)

概念要点
租户 / 开发者空间注册后自动创建,数据相互隔离。tenant_id 数字 ID 在工作台可见;设备 API 调用时不需要显式传租户 ID,平台按 device_id + token 自动定位。
设备 = device_id + tokendevice_id 唯一标识;token 是接入令牌(设备密码)。两者与网页登录账号体系无关。请求用 HTTP Basic(user=device_id, pass=token)或自定义头,见 1.4
属性 props设备上报的数据,平台合并成「属性快照」。只接受标量 / null;同键「新增或值变化」才触发规则。属性名大小写敏感。
指令 command(拉取式)后台 / 规则 / 公开页产生的指令先入队,设备主动 GET 拉取;拉取即标记 sent,不代表执行成功,执行后建议回传结果(见 1.7)。
OTA 固件升级网页端上传固件 / 源码 → 平台审查 / 编译 → 推送设备。设备侧只做「收到 type=ota 指令 → 调 ?action=ota_download&job_id=... 下载固件(成功返回二进制流,不是 JSON)→ 校验 X-OTA-SHA256 → 写入 OTA 分区重启」。固件与云盘共享 10MB 配额,下载窗口 24 小时(见 2.11)。
规则 / 应用规则 = 触发器 + 条件 + 动作(网页配置,无需写代码);应用 = 可视化拖拽出的公开页,可绑定属性展示、绑定按钮下发指令。

1.2 接入全流程(五步)

  1. 注册登录:打开平台官网注册,自动获得独立租户空间。
  2. 创建设备:设备管理 → 新建,填 device_id 与名称,保存后拿到 token(32 位随机串;可随时重置,重置后旧令牌立即失效)。
  3. 设备侧联网:实现三个动作——定时心跳(推荐 30s)、定时上报属性(推荐 20s)、定时拉取指令(推荐 15s),三个定时互相独立。
  4. 联调验证:curl 跑通后,到平台「设备详情 → 属性快照 / 设备日志」确认数据真实到达。
  5. 进阶:配规则引擎做自动化;把属性绑到可视化应用并发布公开链接(可选对接公开 JSON 子接口,见老手版)。

1.3 三个核心接口速查

统一入口:https://www.hjyiot.cn/api.php,用 ?action=xxx 区分接口。

接口方法用途请求体
?action=heartbeatPOST / GET心跳 / 上线(不处理请求体里的属性数据)可省略;如需带 ts 也可 {"ts":...}
?action=reportPOST上报属性(合并进属性快照,触发属性类规则){"ts":...,"props":{"temperature":23.5}}
?action=commandGET拉取待执行指令(同时视为一次心跳);推送 OTA 后也会从这里拿到 type=ota 指令
?action=ota_downloadGET / POST按需使用:下载本设备待升级的 OTA 固件(成功返回二进制流,不是 JSONjob_id(query 或 body,必填)

heartbeat —— 心跳 / 上线

curl -u "device_id:token" -X POST "https://www.hjyiot.cn/api.php?action=heartbeat"
# => {"code":0,"msg":"成功","data":{"online":1,"server_ts":1728000000,"last_seen":1728000000,"rate":null}}

report —— 属性上报

curl -u "device_id:token" -X POST -H 'Content-Type: application/json' \
  -d '{"ts":1728000000,"props":{"temperature":26.5,"humidity":58}}' \
  "https://www.hjyiot.cn/api.php?action=report"
# => {"code":0,"msg":"成功","data":{"accepted":1,"props":{"temperature":26.5,"humidity":58},"server_ts":1728000000,"online":1}}

command —— 拉取待执行指令

curl -u "device_id:token" "https://www.hjyiot.cn/api.php?action=command"
# => {"code":0,"msg":"成功","data":{"online":1,"server_ts":...,"commands":[
#       {"id":"65f1a2b3c4d5e6f7","type":"command","payload":{"fan_on":1},"source":"rule:8","status":"sent","ts":...,"sent_at":...} ]}}

无待执行指令时 commands 为空数组。已 sent 的指令不会重复出现,请勿反复只拉不执行。

固件下载另见老手版 2.11:需租户 OTA 已开启、云盘未封禁、任务未被冻结且处于「可推送 / 已推送」状态,并且要在最近一次推送后 24 小时内;失败返回 JSON 错误码 1002 / 1003 / 1004 / 1006

1.4 鉴权(二选一,均与网页登录态无关)

方式说明示例
HTTP Basic(推荐)用户名 = device_id,密码 = tokencurl -u "device_id:token" ...,HTTP 客户端大多自动做 base64
自定义请求头同时携带两个 HeaderX-Device-ID: <device_id> + X-Device-Token: <token>
凭据错误、设备不存在或已停用,统一返回 code=1001(HTTP 401),且提示不区分具体原因——这是平台的安全设计,避免探测有效设备。

1.5 通用约定

  • 请求与响应均为 UTF-8 JSON;上报接口请带 Content-Type: application/json
  • 统一返回结构 {"code":0,"msg":"成功","data":{...}}code=0 成功,判断结果以业务字段 code 为准(HTTP 状态码仅供参考)。注意字段名是 msg 不是 message
  • 建议所有请求携带 Unix 秒级 ts(设备侧做好 NTP 校时)。当前版本把 ts 记入设备日志供回溯,尚未强制差值拒收;请保持携带以兼容后续强校验版本。
  • 频率限制:按来源 IP 与设备双重限流(阈值见老手版),超限返回 code=1005

1.6 一条龙 curl 联调(把下面的值换成你自己的)

DEVICE_ID="your-device-001"
DEVICE_TOKEN="你的设备token"
API="https://www.hjyiot.cn/api.php"

# 1) 心跳上线
curl -u "$DEVICE_ID:$DEVICE_TOKEN" -X POST "$API?action=heartbeat"

# 2) 属性上报
curl -u "$DEVICE_ID:$DEVICE_TOKEN" -X POST -H 'Content-Type: application/json' \
  -d '{"ts":'$(date +%s)',"props":{"temperature":26.5,"humidity":58}}' "$API?action=report"

# 3) 拉取待执行指令
curl -u "$DEVICE_ID:$DEVICE_TOKEN" "$API?action=command"

# 4) 执行完成回传结果(示例:last_cmd 记最近指令 ID、cmd_ts 记时间、业务状态 fan_on)
curl -u "$DEVICE_ID:$DEVICE_TOKEN" -X POST -H 'Content-Type: application/json' \
  -d '{"ts":'$(date +%s)',"props":{"fan_on":1,"last_cmd":"65f1a2b3c4d5e6f7","cmd_ts":'$(date +%s)'}}' "$API?action=report"

1.7 推荐节奏与指令闭环

参考节奏(互相独立的三个定时器):心跳 30s / 属性上报 20s / 拉取指令 15s。若设备是电池供电 / 低频场景,可自行放宽,但至少保证周期性心跳维持在线判定。

指令闭环四步:① 平台产生指令入队(手动 / 规则 / 公开页按钮);② 设备 command 拉取(拉取即标记 sent 并返回全部待执行指令);③ 设备逐条执行 type + payload 对应业务动作;④ 执行结果用 report 回写为属性,建议使用 last_cmd(最近指令 ID)+ cmd_ts(执行时间)+ 业务状态键(如 fan_on)。这样规则 / 页面 / 快照都能看到执行结果,形成完整闭环。

指令字段:id(16 位十六进制,用于去重与回传关联)、type(自定义,默认 command)、payload(参数对象)、source(来源:manual / rule:<ID> / public_app:<ID>)。平台保留最近 200 条已发送记录供追溯。

1.8 规则引擎与可视化应用(快速入门)

规则引擎:登录后「规则引擎 → 新建规则」,可视化配置即可。触发器 4 类:设备属性上报 / 设备状态变化(上线)/ 定时 cron / Webhook;条件支持 > < >= <= == !=、contains、startswith、endswith、matches;动作 5 类:下发设备指令 / 触发链式规则 / HTTP 请求外部接口 / 站内通知 / 修改设备属性。执行历史在「执行日志」可查。

可视化应用:「应用工作台 → 新建应用」,拖组件(文本 / 指标 / 仪表盘 / 折线图 / 开关 / 按钮 / 分隔线)→ 绑定设备属性或配置指令模板 → 保存发布 → 得到免登录公开链接,可分享、可重置密钥、可下架。开关 / 按钮组件在公开页可直接点击,平台会把指令写入目标设备队列。

如果你在自研前端 / 大屏,想直接读公开页数据或触发按钮,公开页提供 JSON 子接口(&data=1 读快照、&cmd=1 白名单指令下发),细节见 老手版 2.6

1.9 常见报错排查

现象 / 返回原因与处理
code=1001(HTTP 401)鉴权失败:device_id / token 不对、设备不存在或已停用。先到设备详情核对并复制 token(注意不要多复制空格),必要时重置 token。
code=1004(HTTP 413)参数校验失败:请求体为空 / 非对象 / props 不是对象 / 属性含数组对象 / 单包超过 256KB / 未知 action。
code=1005请求频率超限:命中了 IP 或设备级限流,稍等再试,并检查是否有死循环在疯狂请求。
上报成功但规则 / 页面不触发属性名大小写不一致;同值重复上报不会重复触发(平台按「新增或值变化」触发)。
指令拉不到 / 收不到确认指令已入队(后台下发 / 规则动作 / 公开页按钮);确认设备在用同一个 device_id + token 拉取;拉取间隔不要太长。

1.10 再进一步

  • 需要完整协议细节(限流阈值、错误码全表、公开页子接口、Webhook、ESP32 示例)→ 看 老手版
  • 需要把真实开发板接进来 → 老手版附 ESP32 Arduino 最小示例(心跳 30s / 上报 20s / 拉指令 15s)。
  • 遇到平台页面使用问题 → 回顶部切「零基础版」看对应功能说明,或直接联系官方客服 QQ。

⚫ 老手版 · 协议细节直读

面向有嵌入式 / 后端经验的开发者。假设你熟悉 HTTP、Basic Auth、JSON 与队列语义。本版只给「规格」和「坑」,不再做科普。

2.1 端点总览

端点用途鉴权
https://www.hjyiot.cn/api.php?action=heartbeat|report|command设备接入:心跳 / 属性上报 / 指令拉取Basic(user=device_id, pass=token)或 X-Device-ID + X-Device-Token;与登录态无关
https://www.hjyiot.cn/api.php?action=disk_stats|disk_list|disk_read设备云盘(只读三接口):空间概览 / 列目录 / 读文件;同一租户所有设备共享。云盘内容的写入、覆盖、删除不设独立 API,统一在 ?action=report 包内携带 fs[] 指令完成同设备通道(Basic 或双 Header)
http://www.hjyiot.cn/app.php?app=<app_id>&k=<share_key>已发布应用的免登录公开页 + JSON 子接口URL 携带 share_key(app_id + share_key)
http://www.hjyiot.cn/webhook.php?tenant_id=<租户ID>&key=<规则密钥>&path=<触发路径>第三方 POST 触发规则(Webhook 触发器)URL 携带 tenant_id + key + path
https://www.hjyiot.cn/api.php?action=ota_download&job_id=<任务ID>设备 OTA:下载本设备待升级的固件;成功后返回二进制流(非 JSON),失败返回 JSON 错误包同设备通道(Basic 或双 Header)

2.2 鉴权与安全语义

  • 设备通道每次请求必须携带凭据:Authorization: Basic base64(device_id:token),或双 Header X-Device-ID + X-Device-Token
  • 凭据错误 / 设备不存在 / 设备停用 / 租户停用:统一 code=1001(HTTP 401),不区分原因。
  • IP 级限流先于鉴权执行(防爆破),凭据错误同样计数。
  • token 为 32 位随机串,可由用户重置;重置后旧 token 立即失效。
  • 公开页以 app_id + share_key 为凭据;重置 share_key 使旧链接立即失效。

2.3 设备接口规格

统一返回 {"code":0,"msg":"成功","data":{...}};以业务字段 code 判断结果(注意 msg 而非 message)。请求 / 响应 UTF-8 JSON;上报带 Content-Type: application/json

action方法请求返回 data 要点
heartbeatPOST / GET可省略;不处理请求体属性online, server_ts, last_seen, rate;离线→在线转换触发「上线」状态类规则
reportPOST{"ts":<unix>,"props":{...}}accepted, props, server_ts, online
commandGETonline, server_ts, commands[];拉取即全部标记 sent,并视为一次心跳;OTA 推送后其中含 type=ota 指令
ota_downloadGET / POSTjob_id(query 或 body,必填)非 JSON:成功为 application/octet-stream 固件流 + X-OTA-Version / X-OTA-SHA256 / X-OTA-Size / X-OTA-Job 响应头;失败为 {"code":1002|1003|1004|1006,...}

report 细则

  • 属性值仅接受标量 / null(数字 / 字符串 / 布尔);嵌套对象 / 数组被丢弃。
  • 推荐统一 {"ts":...,"props":{...}};兼容平铺写法(如 {"temperature":23.5}),但平铺时除属性外的字段(含 ts)也会并入快照,不建议混用。
  • 按「新增或值变化」的键触发属性类规则;同值重复上报不重复触发。
  • 单包上限 256KB(超限 HTTP 413 / code=1004);空体 / 非对象 / props 非对象均 code=1004

command 队列语义

  • 指令字段:id(16 位十六进制,执行去重与回传关联;字段名是 id 不是 command_id)、type(下发方自定义,默认 command)、payloadsource(manual / rule:<ID> / public_app:<ID>)、status(返回即 sent)、ts(入队)、sent_at(标记 sent 时间)。
  • 已 sent 指令不会在后续拉取中重复出现;平台保留最近 200 条已发送记录供追溯。
  • 执行完成后用 report 回传建议键:last_cmd=最近指令 ID、cmd_ts=执行时间、叠加业务状态键。

ota_download 细则

  • 成功响应不是 {"code":0,...} 包裹,而是固件字节流;请先判 Content-Type 再决定「按流处理」还是「按 JSON 解析错误」。
  • 平台校验顺序:租户 OTA 已开启 → 云盘未被封禁 → 任务存在且属于本设备 → 未被平台冻结 → 状态为 ready / pushed → 处于推送后 24 小时窗口内 → 固件文件存在。
  • 失败码:1002(OTA 功能停用 / 云盘封禁 / 固件被冻结)、1003(任务不存在,两种原因同一提示以防跨设备探测)、1004(缺 job_id / 固件未就绪 / 下载窗口过期)、1006(固件文件缺失或读取失败)。
  • 下载计入设备级限流(120 次 / 分钟);固件响应 Cache-Control: no-store,不做缓存。

2.4 限流与错误码(全站统一规范)

限流层级阈值时机
IP 级(设备通道)600 次 / 分钟 / IP先于鉴权执行,凭据错误也计数
设备级(设备通道)120 次 / 分钟 / 设备鉴权通过后按设备计数
公开页读(data=1)300 次 / 分钟 / IP公开 JSON 读接口
公开页写(cmd=1)60 次 / 分钟 / IP公开 JSON 写接口
code含义典型场景
0成功
1001鉴权失败device_id / token 错误、设备不存在或停用、租户停用
1002权限不足后台管理 API 越权操作等
1003资源不存在按 ID 查不到设备 / 应用 / 规则 / Webhook;disk_read 读取不存在的云盘文件
1004参数校验失败缺请求体、props 非对象、属性含非标量、单包超 256KB(HTTP 413)、未知 action
1005请求频率超限命中任一层限流
1006存储错误平台侧读写异常(极少)
1007MQTT 错误MQTT 通道相关错误
1008设备离线需设备在线才能执行的操作遇离线设备

2.5 规则引擎语义

规则 = 触发器 + 条件(0..N)+ 动作(最多 10 条顺序执行)。

维度可选值
触发器device_prop(属性上报且满足条件)/ device_status(上线 / 掉线:在线状态翻转)/ cron(5 段 cron)/ webhook(外部 POST 专属 URL)
条件组合逻辑 all / any;比较符 > < >= <= == !=containsstartswithendswithmatches(正则);Webhook 条件可引用 payload 字段
动作device_command 下发指令 / trigger_rule 触发另一规则(链式,含防环保护)/ http_request 请求外部 URL(POST 默认,可配方法 / 头 / JSON body,超时 3s)/ notify 站内通知(写执行日志与审计)/ set_prop 修改设备属性

执行结果(命中与否、每动作成败)见「规则引擎 → 执行日志」。

2.6 Webhook 触发示例

规则选「Webhook」触发器后,编辑页会生成专属地址(含 tenant_id / key / path)。任意第三方 POST JSON 即可命中,条件可用 payload 字段求值:

curl -X POST -H 'Content-Type: application/json' \
  -d '{"event":"alarm","level":2}' \
  "http://www.hjyiot.cn/webhook.php?tenant_id=<租户ID>&key=<规则密钥>&path=<触发路径>"
# => { "code":0, "msg":"成功", "data":{ "accepted":1, "server_ts":... } }

2.7 公开页 JSON 子接口(自研前端 / 大屏对接)

子接口说明限流
&data=1(GET)实时数据快照:画布绑定设备的 online / last_seen / props 与折线序列 series(历史曲线由设备上报日志还原,最多 60 个点)300 / 分钟 / IP
&cmd=1(POST JSON)下发指令:{"component_id":"组件ID","payload":{...}};仅允许触发画布组件已声明的指令模板(白名单防滥用),payload 可覆盖模板参数60 / 分钟 / IP
# 读数据
curl "http://www.hjyiot.cn/app.php?app=<app_id>&k=<share_key>&data=1"

# 下发指令(component_id 为配置了 command 模板的组件,如 btn_fan)
curl -X POST -H 'Content-Type: application/json' \
  -d '{"component_id":"btn_fan","payload":{"fan_on":1}}' \
  "http://www.hjyiot.cn/app.php?app=<app_id>&k=<share_key>&cmd=1"
公开数据接口为只读语义;请勿把敏感属性绑定到已发布应用的画布。公开页交互(开关 / 按钮)点击后平台校验 share_key 并把指令写入目标设备队列,设备按 command 拉取节奏收到。

2.8 ESP32 Arduino 最小示例(HTTP 接入)

HTTP Basic 鉴权;三独立定时器:心跳 30s / 上报 20s / 拉指令 15s。需安装 ArduinoJson 库。替换 DEVICE_ID / DEVICE_TOKEN / WIFI_SSID / WIFI_PASS

#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>

const char* WIFI_SSID = "你的WiFi名";
const char* WIFI_PASS = "你的WiFi密码";
const char* DEVICE_ID  = "your-device-001";
const char* DEVICE_TOKEN = "你的设备token";
const char* API_BASE = "http://www.hjyiot.cn/api.php";
const unsigned long HEARTBEAT_MS = 30000, REPORT_MS = 20000, PULLCMD_MS = 15000;
unsigned long tH = 0, tR = 0, tP = 0;

bool apiCall(const char* action, const char* body, String& resp) {
    HTTPClient http;
    http.begin(String(API_BASE) + "?action=" + action);
    http.setAuthorization(DEVICE_ID, DEVICE_TOKEN);
    http.setTimeout(5000);
    int code;
    if (body) { http.addHeader("Content-Type", "application/json"); code = http.POST(body); }
    else      { code = http.GET(); }
    if (code == 200) resp = http.getString();
    http.end();
    return code == 200;
}
void reportProps(JsonDocument& props) {
    String body = "{\"ts\":" + String((long)time(nullptr)) + ",\"props\":";
    serializeJson(props, body); body += "}";
    String r; apiCall("report", body.c_str(), r);
}
void setup() {
    Serial.begin(115200);
    configTime(0, 0, "pool.ntp.org", "ntp.aliyun.com");
    WiFi.begin(WIFI_SSID, WIFI_PASS);
    while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }
    String r; apiCall("heartbeat", nullptr, r);          // 上线
    JsonDocument d; d["temperature"] = 26.5; reportProps(d); // 首报
    tH = tR = tP = millis();
}
void loop() {
    unsigned long now = millis();
    if (now - tH >= HEARTBEAT_MS) { tH = now; String r; apiCall("heartbeat", nullptr, r); }
    if (now - tR >= REPORT_MS) {
        tR = now;
        JsonDocument d;
        d["temperature"] = 26.0 + random(0, 100) / 10.0;
        d["humidity"] = 55 + random(0, 20);
        reportProps(d);
    }
    if (now - tP >= PULLCMD_MS) {
        tP = now;
        String resp; if (!apiCall("command", nullptr, resp)) return;
        JsonDocument doc; deserializeJson(doc, resp);
        for (JsonObject c : doc["data"]["commands"].as<JsonArray>()) {
            // 按 c["type"] / c["payload"] 执行具体动作
            JsonDocument result;
            result["last_cmd"] = c["id"] | "";
            result["cmd_ts"] = (long)time(nullptr);
            result["done"] = 1;
            reportProps(result);   // 执行结果回传
        }
    }
    delay(100);
}

2.9 兼容性与易踩坑清单

  • 响应字段是 msg 不是 message;指令字段是 id 不是 command_id
  • 属性名大小写敏感,规则条件与画布绑定需逐字一致。
  • heartbeat 不处理请求体属性;要刷新属性走 report
  • 指令拉取即 sent,勿只拉不执行造成队列堆积(平台保留最近 200 条已发送记录)。
  • 设备通道与公开页子接口各自独立限流;判断请以 code 为准,HTTP 状态仅供参考。
  • 建议所有请求携带 ts(Unix 秒级),当前版本仅记录,未来版本可能强校验差值,请提前做好 NTP 校时。
  • 公开页 cmd=1 仅允许白名单指令模板,需在画布组件配置模板后生效。
  • ota_download 成功返回二进制流:按 Content-Type 分支处理,只有失败才是 JSON;不要用「先解析 JSON」的客户端直接读固件。
  • OTA 指令与普通指令同一队列type=ota,固件信息在 payloadversion / job_id / size / sha256 / ts
  • 固件下载窗口 24 小时(自最近一次推送起算),过期返回 1004,需在网页端重新推送;重复推送会再入队一条 OTA 指令并刷新窗口。
  • OTA 固件与云盘共享 10MB 配额disk_stats.used 是「云盘文件 + 固件」合计;固件只能在「OTA 升级」页删除任务释放。

2.10 云盘接口(只读三接口 + report.fs 内容维护)

每个租户(账户)默认获得 10MB 共享云盘,与租户下全部设备联动共享配额;这 10MB 与 2.11 OTA 固件 合计计算disk_stats.used = 云盘文件 + 固件),固件需在「OTA 升级」页删除任务释放。当前暂不支持扩容,配额写满后自动进入只读态。允许文件类型:txt(UTF-8 文本)、jpg(图片,仅支持读取 / 预览)。云盘不开放整文件上传与下载;设备对云盘的读取走三个独立只读动作,内容维护一律作为「数据伴随操作」随属性上报包执行。

2.10.1 只读三接口

action方法参数返回 data 要点
disk_statsGET / POSTlimit, used, free, percent, read_only, quota_hit, disabled, disabled_reason, file_types(另附 limit_text / used_text / free_text 人类可读容量文本,便于直接展示)
disk_listGET / POSTpath(目录相对路径,可省略=根目录)rel, items[], used, free, limit, percent, read_only, disabled, quota_hititems[] 条目含 name / type(dir|file) / ext / size(字节) / modified(Unix秒) / frozenfrozen=1 表示该文件或所在目录已被平台冻结
disk_readGET / POSTpath(文件完整相对路径,必填)txt:name, ext, size, encoding(utf-8), content(原文);jpg:name, ext, size, content_type(image/jpeg), data(base64);冻结 / 封禁的文件读取会被拒绝
  • 路径均为相对路径(根目录可用空串或 /),不分层级拼接最多 8 层;名称最长 120 字符,不允许以点号开头,不允许 / \ 与控制字符,杜绝 ../ 穿越。
  • 账户被封禁(平台管控)时:即使只读也不放行——disk_stats / disk_list 返回 code=1002 并附封禁原因(disabled_reason),disk_read 统一返回 code=1002「云盘已被平台封禁」;满配额(quota_hit)不影响读取。
  • jpg 仅支持读取 / 平台网页预览;其内容的新增由平台按业务策略维护,设备侧无法上传图片文件。需保存图片时请使用 txt(如 base64 文本流)或联系平台侧开通专属通道。

2.10.2 report.fs:云盘内容维护指令

发送 report 时在请求体顶层携带 fs 数组,平台会先将 fs 剥离(不落入属性存储),逐项执行后逐项回报;任一项失败不影响其它项,也不影响本次属性上报。单包 fs 最多 20 条;每条 writecontent 上限 128KB;整体包仍受 256KB 单包限制。所有写操作都会写入平台审计(后台「云盘 → 审计记录」可查)。

POST https://www.hjyiot.cn/api.php?action=report
Authorization: Basic base64(device_id:token)
Content-Type: application/json

{
  "ts": 1788861130,
  "props": { "temperature": 26.5 },
  "fs": [
    { "op": "write", "path": "logs/2026-09-08.txt", "content": "温度 26.5℃\n", "mode": "append", "create": true },
    { "op": "delete_content", "path": "logs/2026-09-08.txt", "needle": "旧行", "all": false }
  ]
}
# => data.fs[](逐项对应请求顺序):
#    [ {"op":"write","path":"/logs/2026-09-08.txt","ok":true,"bytes":24,"created":1,"mode":"append"},
#      {"op":"delete_content","path":"/logs/2026-09-08.txt","ok":true,"removed":1,"bytes":19} ]
op参数语义与限制
writepath(必填,txt 相对路径)、content(必填,UTF-8)、modeappend 追加=默认 / overwrite 整文件覆盖)、create(0/1,默认 0)仅支持 txt。目标目录或文件不存在时默认报错 error(不回退为自动创建);显式 create:true 才逐级自动创建目录与文件。返回 op/path/ok/bytes/created/mode;文件超出 8MB 上限或配额满拒绝写入
deletepath(必填)删除文件;不支持删除目录(目录删除请走平台网页端「云盘」),根目录与冻结文件拒绝。返回 op/path/ok
delete_contentpath(必填,txt 文件)、needle(必填,要删除的文本片段)、all(0/1,默认 0)仅支持 txt。按子串删除文本内容:all=false(默认)只删除首个匹配,all=true 删除全部匹配;文件中找不到 needle 时两种模式均返回 error。返回 op/path/ok/removed/bytes(bytes 为处理后文件大小)
  • 返回语义:成功项带 ok:true;失败项不中断批次,置 ok:false 并附 error 中文原因(真实文案如「目录不存在:/logs」「文件不存在:/logs/2026-09-08.txt」「该文件已被平台冻结,禁止修改 / 禁止删除」「云盘已被平台封禁,当前仅可查看」「文件中未找到指定内容:xxx」)。
  • 文件级约束:txt/jpg 单文件均 ≤ 8MB;全盘条目总数 ≤ 5000;目录层级 ≤ 8;配额写满后所有 write 拒绝(可先用 disk_stats 判断 quota_hit / read_only)。
  • 平台封禁为账户级(整盘只读且禁止读取);平台冻结为文件 / 目录级(冻结目录下全部文件禁止修改与读取删除)。设备端应把这两类响应当业务异常处理并在本地重试策略中留出间隔。

2.11 OTA 固件下载(设备侧)

平台 OTA 升级闭环:网页端上传固件 / 源码 → 审查 / 编译 → 推送设备 → 设备下载并校验。设备侧只需实现「收到 type=ota 指令 → 调 ota_download 下载固件 → 校验 → 写入 OTA 分区重启」。固件与云盘共享账户 10MB 配额。

2.11.1 前置条件(平台逐项校验,任一不满足只返回 JSON 错误包)

  • 租户 OTA 功能已开启(平台管理端可停用,停用原因对租户可见);
  • 租户云盘未被平台封禁(封禁期间 OTA 上传 / 编译 / 推送 / 删除与设备固件下载同步停用);
  • 任务存在且归属当前鉴权设备(任务不存在或不属于本设备,统一返回 1003 以防跨设备探测);
  • 任务未被平台冻结(返回 1002);
  • 任务状态为 ready(可推送)或 pushed(已推送);
  • 处于下载窗口内:自最近一次推送时间起 24 小时(从未推送则退化为任务可用时间);
  • 该任务对应的固件文件仍留存于平台。

2.11.2 请求与响应

GET  https://www.hjyiot.cn/api.php?action=ota_download&job_id=<任务ID>
POST https://www.hjyiot.cn/api.php?action=ota_download     Body: {"job_id":"<任务ID>"}

# 成功:HTTP 200 + Content-Type: application/octet-stream(响应体即固件,不是 JSON)
#   X-OTA-Version: 1.2.0      (URL 编码,需 decode)
#   X-OTA-SHA256: 9f2c...     (64 位十六进制,下载后必须校验)
#   X-OTA-Size: 512000
#   X-OTA-Job: 65f1a2b3c4d5e6f7      (16 位十六进制任务 ID)
#   Cache-Control: no-store
# 失败:JSON 错误包 {"code":1002|1003|1004|1006,"msg":"...","data":{...}}

# 一行下载(-OJ 按响应头文件名落盘),下完比对 sha256:
curl -u "device_id:token" -OJ "https://www.hjyiot.cn/api.php?action=ota_download&job_id=<任务ID>"
code场景
1002租户 OTA 功能已停用 / 云盘已被平台封禁 / 该固件已被平台冻结
1003OTA 任务不存在(任务不存在或不属于本设备,提示统一以防探测)
1004缺少 job_id / 固件尚未就绪 / 下载窗口已过期
1006固件文件缺失 / 读取失败

2.11.3 与 command 指令联动(type=ota)

推送时平台向设备指令队列写入 type=ota 指令,source 形如 ota:<操作者用户名>id 为 16 位十六进制指令 ID(与 2.3 的指令结构一致),payload 固定为:

{ "version":"1.2.0", "job_id":"65f1a2b3c4d5e6f7", "size":512000,
  "sha256":"9f2c...(64 位十六进制)", "ts":1788600000 }

设备侧推荐流程:① command 拉到 type=ota → ② 从 payloadjob_id / version / size / sha256 → ③ 与本地版本比对(平台已保证版本递增,设备侧建议再判一次防回退)→ ④ ota_download 下载 → ⑤ 校验大小与 SHA-256 → ⑥ 写入 OTA 分区 → ⑦ 重启 → ⑧ 上线后用 report 回写新版本号,形成闭环。

2.11.4 任务状态机(11 态,含租户侧页面显示名)

状态页面显示说明
pending_review待审查上传 .ino 源码后等待隔离审查(页面提示约 10 分钟内完成;仅反馈问题代码位置,平台不代修)
reviewing审查中正在审查
review_fail审查未通过审查未通过(不计编译额度)
queued排队中审查通过,等待编译(页面展示排队位次与预计完成时间)
need_payment待充值编译额度不足,需联系客服充值(3 元 / 次)后继续;此状态仍可直接上传 .bin 免费推送
compiling编译中正在编译;超过 20 分钟未推进由后台 worker 判为中断,回退 queued 下轮自动重试
compile_fail编译失败编译失败(返回错误与问题代码片段;编译失败同样计费)
ready可推送编译成功或直传 .bin,可推送、可被 ota_download 下载
pushed已推送已推送设备(可重复推送;重复推送刷新下载窗口)
canceled已撤销用户撤销
frozen已冻结平台冻结(阻断编译、推送与下载)
  • 上传限制:.ino ≤ 512KB、.bin ≤ 4MB,仅这两种扩展名;版本号须严格大于该设备已发布最高版本(v / V 前缀会被剥离),长度 ≤ 60;
  • 编译额度:每租户免费 3 次;批量勾选多台设备时每台生成一条独立任务、各占 1 次(同批共用一次编译产物);任务实际进入编译即扣(编译失败同样计费,审查未通过、源文件拉取失败不计费);
  • 其他上限:单次批量推送 ≤ 50 个任务、单租户任务 ≤ 200 个,每任务保留 20 条状态更新(对租户展示最近 10 条);
  • 配额:固件按设备份数计入账户 10MB(与云盘共享),空间不足时上传被拒并写 ota_quota_reject 审计。

2.11.5 任务删除规则

  • queued(排队中)与 compiling(编译中)不可删除:流水线处理中,返回 code=1004,文案「任务当前状态为「排队中/编译中」,流水线处理中不可删除,请等待编译结束后再删除」;
  • 其余状态(pending_review / reviewing / review_fail / need_payment / compile_fail / ready / pushed / canceled / frozen)均可删除;
  • 删除为物理删除:该任务的源码与编译产物一并清理,并释放其占用的账户配额;页面二次确认会展示将释放的容量;
  • 固件只能在「OTA 升级」页删除任务释放,云盘侧不可删除;设备侧不提供删除入口。

2.11.6 审计口径(仅平台管理员可见)

  • OTA 全动作写入独立审计记录(与通用审计、云盘审计并行留存);
  • 审计仅平台管理端「OTA 审计」入口可读租户侧与设备侧均不开放审计查询接口与入口;
  • 常见 action:ota_upload / ota_quota_reject / ota_queued / ota_reviewing / ota_review_fail / ota_compile_fail / ota_ready / ota_need_payment / ota_push / ota_delete,以及平台侧 ota_admin_enable / disable / recharge / freeze / unfreeze / delete;每条含操作者与来源(web / admin / device / system)。

2.11.7 SDK 用法

# Python(hjyiot.py)
from hjyiot import HjyIot
dev = HjyIot("your-device-001", "你的token", base="https://www.hjyiot.cn/api.php")
r = dev.ota_download("65f1a2b3c4d5e6f7", "fw.bin")
# => {"version":"1.2.0","size":512000,"sha256":"9f2c...","sha256_match":true,"path":"fw.bin"}

// ESP32 Arduino(HjyIot.h,流式写入 OTA 分区并边写边算 SHA-256)
HjyIot dev(DEVICE_ID, DEVICE_TOKEN, API_BASE);
String out;
if (dev.otaDownload(jobId, out)) {
    Serial.println(out);   // 含 version / size / sha256 / match
    ESP.restart();
}

两类 SDK 均只做「下载 + 校验 + 落盘 / 落分区」;版本比对与重启时机由业务侧决定

← 返回登录