├── examples ├── Python │ └── demo.py ├── JavaScript │ └── demo.js ├── PHP │ └── demo.php ├── C# │ └── demo.cs ├── C │ └── demo.c └── Java │ └── demo.java ├── docs ├── zh.md ├── de.md ├── fr.md ├── zh_properties.md ├── en_properties.md └── openapi.yaml └── README.md /examples/Python/demo.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Author: dav1d wei.liu@zendure.com 3 | Date: 2025-03-05 14:23:28 4 | LastEditors: dav1d wei.liu@zendure.com 5 | LastEditTime: 2025-03-05 14:23:33 6 | FilePath: /zenSDK/examples/Python/demo.py 7 | Description: 8 | 9 | Copyright (c) 2025 by Zendure, All Rights Reserved. 10 | ''' 11 | import requests 12 | 13 | # GET 请求 14 | get_response = requests.get("http:///properties/report") 15 | print("GET:", get_response.text) 16 | 17 | # POST 请求 18 | post_response = requests.post("http:///properties/write", json={"sn": "your_device_sn", "properties": {"acMode": 2}}) 19 | print("POST:", post_response.text) -------------------------------------------------------------------------------- /examples/JavaScript/demo.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: dav1d wei.liu@zendure.com 3 | * @Date: 2025-03-05 14:22:34 4 | * @LastEditors: dav1d wei.liu@zendure.com 5 | * @LastEditTime: 2025-03-05 14:22:36 6 | * @FilePath: /zenSDK/examples/JavaScript/demo.js 7 | * @Description: 8 | * 9 | * Copyright (c) 2025 by Zendure, All Rights Reserved. 10 | */ 11 | const axios = require('axios'); 12 | 13 | // GET 请求 14 | axios.get('http:///properties/report') 15 | .then(res => console.log("GET:", res.data)); 16 | 17 | // POST 请求 18 | axios.post('http:///properties/write', { sn: "your_device_sn", properties: { acMode: 2 } }) 19 | .then(res => console.log("POST:", res.data)); -------------------------------------------------------------------------------- /examples/PHP/demo.php: -------------------------------------------------------------------------------- 1 | /properties/report"; 14 | echo file_get_contents($get_url); 15 | 16 | // POST 请求 17 | $post_url = "http:///properties/write"; 18 | $data = json_encode(["sn" => "your_device_sn", "properties" => ["acMode" => 2]]); 19 | $options = [ 20 | "http" => [ 21 | "header" => "Content-Type: application/json", 22 | "method" => "POST", 23 | "content" => $data 24 | ] 25 | ]; 26 | echo file_get_contents($post_url, false, stream_context_create($options)); 27 | ?> -------------------------------------------------------------------------------- /examples/C#/demo.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: dav1d wei.liu@zendure.com 3 | * @Date: 2025-03-05 14:14:26 4 | * @LastEditors: dav1d wei.liu@zendure.com 5 | * @LastEditTime: 2025-03-05 14:15:24 6 | * @FilePath: /zenSDK/examples/C#/demo.cpp 7 | * @Description: 8 | * 9 | * Copyright (c) 2025 by Zendure, All Rights Reserved. 10 | */ 11 | using System; 12 | using System.Net.Http; 13 | using System.Threading.Tasks; 14 | 15 | class Program { 16 | static async Task Main() { 17 | var client = new HttpClient(); 18 | 19 | // GET 请求 20 | var getResponse = await client.GetStringAsync("http:///properties/report"); 21 | Console.WriteLine(getResponse); 22 | 23 | // POST 请求 24 | var json = new StringContent("{\"sn\": \"your_device_sn\", \"properties\": {\"acMode\": 2}}", 25 | System.Text.Encoding.UTF8, "application/json"); 26 | var postResponse = await client.PostAsync("http:///properties/write", json); 27 | Console.WriteLine(await postResponse.Content.ReadAsStringAsync()); 28 | } 29 | } -------------------------------------------------------------------------------- /examples/C/demo.c: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: dav1d wei.liu@zendure.com 3 | * @Date: 2025-03-05 14:21:42 4 | * @LastEditors: dav1d wei.liu@zendure.com 5 | * @LastEditTime: 2025-03-05 14:21:47 6 | * @FilePath: /zenSDK/examples/C/demo.c 7 | * @Description: 8 | * 9 | * Copyright (c) 2025 by Zendure, All Rights Reserved. 10 | */ 11 | #include 12 | #include 13 | 14 | void send_get_request() { 15 | CURL *curl = curl_easy_init(); 16 | if (curl) { 17 | curl_easy_setopt(curl, CURLOPT_URL, "http:///properties/report"); 18 | curl_easy_perform(curl); 19 | curl_easy_cleanup(curl); 20 | } 21 | } 22 | 23 | void send_post_request() { 24 | CURL *curl = curl_easy_init(); 25 | if (curl) { 26 | curl_easy_setopt(curl, CURLOPT_URL, "http:///properties/write"); 27 | curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "{\"sn\": \"your_device_sn\", \"properties\": {\"acMode\": 2}}"); 28 | 29 | struct curl_slist *headers = NULL; 30 | headers = curl_slist_append(headers, "Content-Type: application/json"); 31 | curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); 32 | 33 | curl_easy_perform(curl); 34 | curl_easy_cleanup(curl); 35 | } 36 | } 37 | 38 | int main() { 39 | send_get_request(); 40 | send_post_request(); 41 | return 0; 42 | } -------------------------------------------------------------------------------- /examples/Java/demo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: dav1d wei.liu@zendure.com 3 | * @Date: 2025-03-05 14:22:12 4 | * @LastEditors: dav1d wei.liu@zendure.com 5 | * @LastEditTime: 2025-03-05 14:22:17 6 | * @FilePath: /zenSDK/examples/Java/demo.java 7 | * @Description: 8 | * 9 | * Copyright (c) 2025 by Zendure, All Rights Reserved. 10 | */ 11 | import java.io.*; 12 | import java.net.*; 13 | 14 | public class SimpleHttp { 15 | public static void main(String[] args) throws Exception { 16 | // GET 请求 17 | URL getUrl = new URL("http:///properties/report"); 18 | HttpURLConnection getConn = (HttpURLConnection) getUrl.openConnection(); 19 | getConn.setRequestMethod("GET"); 20 | System.out.println("GET Response Code: " + getConn.getResponseCode()); 21 | 22 | // POST 请求 23 | URL postUrl = new URL("http:///properties/write"); 24 | HttpURLConnection postConn = (HttpURLConnection) postUrl.openConnection(); 25 | postConn.setRequestMethod("POST"); 26 | postConn.setRequestProperty("Content-Type", "application/json"); 27 | postConn.setDoOutput(true); 28 | 29 | String json = "{\"sn\": \"your_device_sn\", \"properties\": {\"acMode\": 2}}"; 30 | try (OutputStream os = postConn.getOutputStream()) { 31 | os.write(json.getBytes()); 32 | } 33 | System.out.println("POST Response Code: " + postConn.getResponseCode()); 34 | } 35 | } -------------------------------------------------------------------------------- /docs/zh.md: -------------------------------------------------------------------------------- 1 | 11 | 12 | # 征拓产品本地控制系统 13 | 14 | --- 15 | 16 |

17 | Zendure Logo 18 |

19 | 20 | # 📖 文档导航 21 | 22 | 本项目提供多语言版本文档,选择您需要的语言: 23 | 24 | - 🇨🇳 [中文](./zh.md) 25 | - 🇬🇧 [English](../README.md) 26 | - 🇩🇪 [Deutsch](./de.md) 27 | - 🇫🇷 [Français](./fr.md) 28 | 29 | --- 30 | 31 | # 🌟 概述 32 | 33 | 在过往的[设备数据上报项目](https://github.com/Zendure/developer-device-data-report)实践中,我们发现了本地化控制的优化需求。为此,团队自主研发了物联网架构 **ZenSDK**,现开放**本地 API 接口**,助力开发者实现以下能力: 34 | 35 | - 实时获取设备状态与属性 36 | - 监听设备数据流 37 | - 远程控制设备功能 38 | - 集成第三方 MQTT 客户端(支持 [Home Assistant](https://www.home-assistant.io/integrations/mqtt/)) 39 | - 基于 API 开发个性化功能,提升用户体验 40 | 41 | 如果您对 **Zendure** 产品有创新想法,欢迎随时联系我们! 42 | 43 | --- 44 | 45 | # 📌 支持产品列表 46 | 47 | 当前文档覆盖的产品及固件版本信息如下: 48 | 49 | | 产品型号 | 固件版本 | 备注 | 50 | | ------------------ | ------------ | ---- | 51 | | solarFlow800 | 升级最新版本 | | 52 | | solarFlow800Pro | 升级最新版本 | | 53 | | solarFlow2400AC | 升级最新版本 | | 54 | | smartMeter3CT | 升级最新版本 | | 55 | | (更多产品待更新) | - | | 56 | 57 | --- 58 | 59 | # 🚀 核心功能架构 60 | 61 | 本地控制功能通过 **mDNS 服务发现** 与 **HTTP Server 通信** 协同实现,核心流程如下: 62 | 63 | ## 1. 设备发现机制(mDNS) 64 | 65 | 设备联网启动后,通过 **mDNS(多播 DNS)协议** 广播自身服务信息,包括: 66 | 67 | - 服务名称:`Zendure-<型号>-`(例:`Zendure-SolarFlow800-WOB1NHMAMXXXXX3`) 68 | - IP 地址 69 | - HTTP 服务端口 70 | 71 | 其他设备/客户端通过监听局域网 mDNS 广播,自动发现新设备并获取连接信息。 72 | 73 | ## 2. 设备通信机制(HTTP RESTful API) 74 | 75 | 设备内置 HTTP 服务器,支持以下通信方式: 76 | 77 | ### 基础操作类型 78 | 79 | | 方法 | 用途 | 示例 | 80 | | -------- | --------------------- | ------------------------------------------ | 81 | | `GET` | 查询设备状态/属性 | `GET /properties/report`(获取全量属性) | 82 | | `POST` | 发送控制指令/配置参数 | `POST /properties/write`(设置设备属性) | 83 | 84 | ### 数据格式规范 85 | 86 | - **GET 请求**:无请求体,响应为 JSON 格式设备属性。 87 | - **POST 请求**:需携带 JSON 格式请求体,字段需包含设备序列号 `sn`(必填)。 88 | 89 | #### 示例 1:获取设备属性 90 | 91 | ```http 92 | GET /properties/report 93 | ``` 94 | 95 | #### 示例 2:发送控制指令/配置参数 96 | 97 | ```http 98 | POST /properties/write 99 | Content-Type: application/json 100 | 101 | { 102 | "sn": "WOB1NHMAMXXXXX3", // Required 103 | "properties": { 104 | "acMode": 2 // Corresponding readable/writable attribute 105 | } 106 | } 107 | ``` 108 | 109 | #### 示例 3:获取MQTT连接情况 110 | 111 | ```http 112 | GET /rpc?method=HA.Mqtt.GetStatus 113 | ``` 114 | 115 | #### 示例 4:获取MQTT配置参数 116 | 117 | ```http 118 | GET /rpc?method=HA.Mqtt.GetConfig 119 | ``` 120 | 121 | #### 示例 5:设置 MQTT 配置(POST) 122 | 123 | ```http 124 | POST /rpc 125 | Content-Type: application/json 126 | 127 | { 128 | "sn": "WOB1NHMAMXXXXX3", 129 | "method": "HA.Mqtt.SetConfig", 130 | "params": { 131 | "config": { 132 | "enable": true, 133 | "server": "192.168.50.48", 134 | "port":1883, 135 | "protocol":"mqtt", 136 | "username": "zendure", 137 | "password": "zendure" 138 | } 139 | } 140 | } 141 | ``` 142 | 143 | --- 144 | 145 | # 🛠️ 开发工具支持 146 | 147 | ## 系统级 mDNS 服务发现 148 | 149 | | 操作系统 | 命令示例 | 说明 | 150 | | -------- | --------------------------------- | --------------------------------------------- | 151 | | Windows | `Get-Service | Where-Object { $_.Name -like "*Bonjour*" }` | 152 | | macOS | `dns-sd -B _zendure._tcp` | 浏览局域网 Zendure 设备 | 153 | | Linux | `avahi-browse -r _zendure._tcp` | 发现 _zendure._tcp 服务 | 154 | 155 | ## 多语言调用示例 156 | 157 | - [C 语言示例](../examples/C/demo.c) 158 | - [C# 示例](../examples/C%23/demo.cs) 159 | - [Java 示例](../examples/Java/demo.java) 160 | - [JavaScript 示例](../examples/JavaScript/demo.js) 161 | - [PHP 示例](../examples/PHP/demo.php) 162 | - [Python 示例](../examples/Python/demo.py) 163 | - [命令行测试](#命令行快速测试) 164 | 165 | ### 命令行快速测试 166 | 167 | ```bash 168 | # 获取设备全量属性 169 | curl -X GET "http:///properties/report" 170 | 171 | # 查询 MQTT 配置状态 172 | curl -X GET "http:///rpc?method=HA.Mqtt.GetStatus" 173 | 174 | # 设置 设备 acMode属性 175 | curl -X POST "http:///properties/write" \ 176 | -H "Content-Type: application/json" \ 177 | -d '{"sn": "your_device_sn","properties":{"acMode":2}}' 178 | ``` 179 | 180 | --- 181 | 182 | # 📚 产品属性详解 183 | 184 | 各产品具体属性定义及说明,详见: 185 | [SolarFlow系列属性文档](./zh_properties.md) 186 | 187 | --- 188 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Zendure Local Control System 2 | 3 | --- 4 | 5 |

6 | Zendure Logo 7 |

8 | 9 | # 📖 Documentation Navigator 10 | 11 | This project offers documentation in multiple languages. Choose the one you need: 12 | 13 | * 🇨🇳 [中文 ](./docs/zh.md) 14 | * 🇬🇧 [English](./README.md) 15 | * 🇩🇪 [Deutsch](./docs/de.md) 16 | * 🇫🇷 [Français](./docs/fr.md) 17 | 18 | --- 19 | 20 | # 🌟 Overview 21 | 22 | During the development of our previous [Device Data Report Project](https://github.com/Zendure/developer-device-data-report) we identified a strong need for improved local control.As a response, the team created the IoT framework **ZenSDK** and is now opening the **Local API** to help developers achieve: 23 | 24 | - Real-time device status & property retrieval 25 | - Event stream subscription 26 | - Remote function control 27 | - Integration of third-party MQTT clients (including [Home Assistant](https://www.home-assistant.io/integrations/mqtt/)) 28 | - Custom feature development through open APIs to enhance user experience 29 | 30 | Have an innovative idea for **Zendure** products? Feel free to reach out! 31 | 32 | --- 33 | 34 | # 📌 Supported Products 35 | 36 | | Model | Firmware Version | Status | 37 | | ------------------ | ---------------- | ------ | 38 | | SolarFlow800 | Latest | | 39 | | SolarFlow800 Pro | Latest | | 40 | | SolarFlow2400 AC | Latest | | 41 | | SmartMeter3CT | Latest | | 42 | | (More coming soon) | – | | 43 | 44 | --- 45 | 46 | # 🚀 Core Architecture 47 | 48 | Local control is achieved via a combination of **mDNS service discovery** and **HTTP server communication**: 49 | 50 | ## 1. Device Discovery (mDNS) 51 | 52 | After connecting to the network, the device broadcasts its service information through **mDNS**: 53 | 54 | - Service name: `Zendure--`(e.g. `Zendure-SolarFlow800-WOB1NHMAMXXXXX3`) 55 | - IP address 56 | - HTTP service port 57 | 58 | Clients on the same LAN can listen for these broadcasts to automatically discover devices. 59 | 60 | ## 2. Device Communication (HTTP RESTful API) 61 | 62 | Each device hosts an internal HTTP server. 63 | 64 | ### Basic Operations 65 | 66 | | Method | Purpose | Example | 67 | | -------- | ------------------------------ | ------------------------------------------- | 68 | | `GET` | Query device status/properties | `GET /properties/report` (all properties) | 69 | | `POST` | Send control/config commands | `POST /properties/write` (set properties) | 70 | 71 | ### Data Format 72 | 73 | - **GET**: No body, response in JSON. 74 | - **POST**: JSON body must include device serial number `sn` (required). 75 | 76 | #### Example 1: Get device properties 77 | 78 | ```http 79 | GET /properties/report 80 | ``` 81 | 82 | #### Example 2: Send control/config command 83 | 84 | ```http 85 | POST /properties/write 86 | Content-Type: application/json 87 | 88 | { 89 | "sn": "WOB1NHMAMXXXXX3", // Required 90 | "properties": { 91 | "acMode": 2 // Writable property 92 | } 93 | } 94 | ``` 95 | 96 | #### Example 3: Check MQTT status 97 | 98 | ```http 99 | GET /rpc?method=HA.Mqtt.GetStatus 100 | ``` 101 | 102 | #### Example 4: Get MQTT configuration 103 | 104 | ```http 105 | GET /rpc?method=HA.Mqtt.GetConfig 106 | ``` 107 | 108 | #### Example 5: Set MQTT configuration 109 | 110 | ```http 111 | POST /rpc 112 | Content-Type: application/json 113 | 114 | { 115 | "sn": "WOB1NHMAMXXXXX3", 116 | "method": "HA.Mqtt.SetConfig", 117 | "params": { 118 | "config": { 119 | "enable": true, 120 | "server": "192.168.50.48", 121 | "port":1883, 122 | "protocol":"mqtt", 123 | "username": "zendure", 124 | "password": "zendure" 125 | } 126 | } 127 | } 128 | ``` 129 | 130 | --- 131 | 132 | # 🛠️ Development Tools 133 | 134 | ## System-level mDNS discovery commands 135 | 136 | | OS | Command example | Description | 137 | | ------- | ------------------------------------------------------------ | ----------------------------------- | 138 | | Windows | `Get-Service \| Where-Object { $_.Name -like "*Bonjour*" }` | Check Bonjour service | 139 | | macOS | `dns-sd -B _zendure._tcp` | Browse Zendure devices | 140 | | Linux | `avahi-browse -r _zendure._tcp` | Discover `_zendure._tcp` services | 141 | 142 | ## Multi-language Samples 143 | 144 | - [C](./examples/C/demo.c) 145 | - [C#](./examples/C%23/demo.cs) 146 | - [Java](./examples/Java/demo.java) 147 | - [JavaScript](./examples/JavaScript/demo.js) 148 | - [PHP](./examples/PHP/demo.php) 149 | - [Python](./examples/Python/demo.py) 150 | - [CLI quick test](#command-line-quick-test) 151 | 152 | ### Command-line quick test 153 | 154 | ```bash 155 | # Get all properties 156 | curl -X GET "http:///properties/report" 157 | 158 | # Query MQTT status 159 | curl -X GET "http:///rpc?method=HA.Mqtt.GetStatus" 160 | 161 | # Set acMode property 162 | curl -X POST "http:///properties/write" \ 163 | -H "Content-Type: application/json" \ 164 | -d '{"sn": "your_device_sn", "properties": { "acMode": 2 }}' 165 | ``` 166 | 167 | --- 168 | 169 | # 📚 Property Reference 170 | 171 | Detailed property definitions for each product: 172 | [SolarFlow Series Property Doc](./docs/en_properties.md) 173 | 174 | --- 175 | -------------------------------------------------------------------------------- /docs/de.md: -------------------------------------------------------------------------------- 1 | # Zendure Lokales Steuersystem 2 | 3 | --- 4 | 5 |

6 | Zendure Logo 7 |

8 | 9 | # 📖 Dokumenten­navigation 10 | 11 | Dieses Projekt stellt mehrsprachige Dokumente bereit. Wählen Sie Ihre Sprache : 12 | 13 | * 🇨🇳 [中文](./zh.md) 14 | * 🇬🇧 [English](../README.md) 15 | * 🇩🇪 [Deutsch](./de.md) 16 | * 🇫🇷 [Français](./fr.md) 17 | 18 | --- 19 | 20 | # 🌟 Überblick 21 | 22 | In unserem vorherigen [Device-Data-Report-Projekt](https://github.com/Zendure/developer-device-data-report) zeigte sich ein klarer Bedarf an optimierter lokaler Steuerung.Daraufhin entwickelte das Team das IoT-Framework **ZenSDK** und veröffentlicht nun seine **lokale API**, mit der Entwickler Folgendes realisieren können : 23 | 24 | - Abruf von Gerätestatus und -eigenschaften in Echtzeit 25 | - Abonnieren von Geräte-Datenströmen 26 | - Fernsteuerung von Gerätefunktionen 27 | - Anbindung beliebiger MQTT-Clients (u. a. [Home Assistant](https://www.home-assistant.io/integrations/mqtt/)) 28 | - Entwicklung individueller Features über offene APIs zur Steigerung des Benutzererlebnisses 29 | 30 | Haben Sie innovative Ideen zu **Zendure**-Produkten? Kontaktieren Sie uns gern! 31 | 32 | --- 33 | 34 | # 📌 Unterstützte Produkte 35 | 36 | | Modell | Firmware-Version | Status | 37 | | ---------------- | ---------------- | ------ | 38 | | SolarFlow800 | Neueste | | 39 | | SolarFlow800 Pro | Neueste | | 40 | | SolarFlow2400 AC | Neueste | | 41 | | SmartMeter3CT | Neueste | | 42 | | | | | 43 | 44 | --- 45 | 46 | # 🚀 Kernarchitektur 47 | 48 | Die lokale Steuerung basiert auf der Kombination aus **mDNS-Service­-Discovery** und **HTTP-Server-Kommunikation**. 49 | 50 | ## 1. Geräteerkennung (mDNS) 51 | 52 | Nach dem Netzstart sendet das Gerät mittels **mDNS** folgende Informationen : 53 | 54 | - Service-Name: `Zendure--`(z. B. `Zendure-SolarFlow800-WOB1NHMAMXXXXX3`) 55 | - IP-Adresse 56 | - HTTP-Port 57 | 58 | Clients im selben LAN können diese Broadcasts empfangen und Geräte automatisch entdecken. 59 | 60 | ## 2. Geräteschnittstelle (HTTP-RESTful API) 61 | 62 | Jedes Gerät betreibt einen internen HTTP-Server. 63 | 64 | ### Grundoperationen 65 | 66 | | Methode | Zweck | Beispiel | 67 | | -------- | ----------------------------------- | ------------------------------------------------- | 68 | | `GET` | Gerätestatus / Eigenschaften lesen | `GET /properties/report` (alle Eigenschaften) | 69 | | `POST` | Steuer- oder Konfig-Befehle senden | `POST /properties/write` (Eigenschaften setzen) | 70 | 71 | ### Datenformate 72 | 73 | - **GET**: Kein Request-Body, Antwort in JSON 74 | - **POST**: JSON-Body, Pflichtfeld `sn` (Seriennummer) 75 | 76 | #### Beispiel 1: Eigenschaften abfragen 77 | 78 | ```http 79 | GET /properties/report 80 | ``` 81 | 82 | #### Beispiel 2: Steuer-/Konfig­-Befehl senden 83 | 84 | ```http 85 | POST /properties/write 86 | Content-Type: application/json 87 | 88 | { 89 | "sn": "WOB1NHMAMXXXXX3", // Pflicht 90 | "properties": { 91 | "acMode": 2 // Schreibbare Eigenschaft 92 | } 93 | } 94 | ``` 95 | 96 | #### Beispiel 3: MQTT-Status prüfen 97 | 98 | ```http 99 | GET /rpc?method=HA.Mqtt.GetStatus 100 | ``` 101 | 102 | #### Beispiel 4: MQTT-Konfiguration abrufen 103 | 104 | ```http 105 | GET /rpc?method=HA.Mqtt.GetConfig 106 | ``` 107 | 108 | #### Beispiel 5: MQTT-Konfiguration setzen 109 | 110 | ```http 111 | POST /rpc 112 | Content-Type: application/json 113 | 114 | { 115 | "sn": "WOB1NHMAMXXXXX3", 116 | "method": "HA.Mqtt.SetConfig", 117 | "params": { 118 | "config": { 119 | "enable": true, 120 | "server": "192.168.50.48", 121 | "port":1883, 122 | "protocol":"mqtt", 123 | "username": "zendure", 124 | "password": "zendure" 125 | } 126 | } 127 | } 128 | ``` 129 | 130 | --- 131 | 132 | # 🛠️ Entwicklungswerkzeuge 133 | 134 | ## mDNS-Erkennung auf Systemebene 135 | 136 | | Betriebssystem | Beispielbefehl | Beschreibung | 137 | | -------------- | ------------------------------------------------------------ | ------------------------------------ | 138 | | Windows | `Get-Service \| Where-Object { $_.Name -like "*Bonjour*" }` | Bonjour-Dienst prüfen | 139 | | macOS | `dns-sd -B _zendure._tcp` | Zendure-Geräte durchsuchen | 140 | | Linux | `avahi-browse -r _zendure._tcp` | Services `_zendure._tcp` entdecken | 141 | 142 | ## Code-Beispiele 143 | 144 | - [C](../examples/C/demo.c) 145 | - [C#](../examples/C%23/demo.cs) 146 | - [Java](../examples/Java/demo.java) 147 | - [JavaScript](../examples/JavaScript/demo.js) 148 | - [PHP](../examples/PHP/demo.php) 149 | - [Python](../examples/Python/demo.py) 150 | - [CLI-Schnelltest](#cli-schnelltest) 151 | 152 | ### CLI-Schnelltest 153 | 154 | ```bash 155 | # Alle Eigenschaften abrufen 156 | curl -X GET "http:///properties/report" 157 | 158 | # MQTT-Status prüfen 159 | curl -X GET "http:///rpc?method=HA.Mqtt.GetStatus" 160 | 161 | # acMode-Eigenschaft setzen 162 | curl -X POST "http:///properties/write" \ 163 | -H "Content-Type: application/json" \ 164 | -d '{"sn": "your_device_sn", "properties": { "acMode": 2 }}' 165 | ``` 166 | 167 | --- 168 | 169 | # 📚 Eigenschaftsreferenz 170 | 171 | Detaillierte Eigenschaftsbeschreibungen je Produkt finden Sie hier : 172 | [SolarFlow-Serien-Eigenschaften](./de_properties.md) 173 | 174 | --- 175 | -------------------------------------------------------------------------------- /docs/fr.md: -------------------------------------------------------------------------------- 1 | # Système de Contrôle Local Zendure 2 | 3 | --- 4 | 5 |

6 | Logo Zendure 7 |

8 | 9 | # 📖 Navigation dans la documentation 10 | 11 | Ce projet propose une documentation multilingue ; choisissez votre langue : 12 | 13 | * 🇨🇳 [中文](./zh.md) 14 | * 🇬🇧 [English](../README.md) 15 | * 🇩🇪 [Deutsch](./de.md) 16 | * 🇫🇷 [Français](./fr.md) 17 | 18 | --- 19 | 20 | # 🌟 Vue d’ensemble 21 | 22 | Au cours de notre précédent projet [Device Data Report](https://github.com/Zendure/developer-device-data-report), nous avons constaté la nécessité d’une commande locale améliorée.Pour y répondre, nous avons créé le framework IoT **ZenSDK** et ouvrons maintenant son **API locale** afin de permettre aux développeurs de : 23 | 24 | - Obtenir en temps réel l’état et les propriétés des appareils 25 | - S’abonner aux flux de données des appareils 26 | - Contrôler à distance les fonctions des appareils 27 | - Intégrer des clients MQTT tiers (y compris [Home Assistant](https://www.home-assistant.io/integrations/mqtt/)) 28 | - Développer des fonctionnalités personnalisées via des API ouvertes pour améliorer l’expérience utilisateur 29 | 30 | Une idée innovante autour des produits **Zendure** ? Contactez-nous ! 31 | 32 | --- 33 | 34 | # 📌 Produits pris en charge 35 | 36 | | Modèle | Version du firmware | Statut | 37 | | --------------------- | ------------------- | ------ | 38 | | SolarFlow800 | Dernière | | 39 | | SolarFlow800 Pro | Dernière | | 40 | | SolarFlow2400 AC | Dernière | | 41 | | SmartMeter3CT | Dernière | | 42 | | (Bientôt disponible) | – | | 43 | 44 | --- 45 | 46 | # 🚀 Architecture principale 47 | 48 | La commande locale repose sur la **découverte de service mDNS** associée à une **communication HTTP**. 49 | 50 | ## 1. Découverte des appareils (mDNS) 51 | 52 | Après connexion au réseau, l’appareil diffuse via **mDNS** : 53 | 54 | - Nom de service : `Zendure--<12derniersMAC>`(ex. : `Zendure-SolarFlow800-WOB1NHMAMXXXXX3`) 55 | - Adresse IP 56 | - Port du service HTTP 57 | 58 | Les clients du même réseau local peuvent écouter ces diffusions pour détecter automatiquement les appareils. 59 | 60 | ## 2. Interface de communication (API HTTP RESTful) 61 | 62 | Chaque appareil embarque un serveur HTTP interne. 63 | 64 | ### Opérations de base 65 | 66 | | Méthode | Objet | Exemple | 67 | | -------- | -------------------------------- | ---------------------------------------------------- | 68 | | `GET` | Lire l’état / les propriétés | `GET /properties/report` (toutes les propriétés) | 69 | | `POST` | Envoyer des commandes / configs | `POST /properties/write` (écrire une propriété) | 70 | 71 | ### Formats de données 72 | 73 | - **GET** : pas de corps, réponse JSON. 74 | - **POST** : corps JSON contenant obligatoirement le numéro de série `sn`. 75 | 76 | #### Exemple 1 : lire les propriétés 77 | 78 | ```http 79 | GET /properties/report 80 | ``` 81 | 82 | #### Exemple 2 : écrire une propriété / configurer 83 | 84 | ```http 85 | POST /properties/write 86 | Content-Type: application/json 87 | 88 | { 89 | "sn": "WOB1NHMAMXXXXX3", // Obligatoire 90 | "properties": { 91 | "acMode": 2 // Propriété modifiable 92 | } 93 | } 94 | ``` 95 | 96 | #### Exemple 3 : vérifier l’état MQTT 97 | 98 | ```http 99 | GET /rpc?method=HA.Mqtt.GetStatus 100 | ``` 101 | 102 | #### Exemple 4 : obtenir la configuration MQTT 103 | 104 | ```http 105 | GET /rpc?method=HA.Mqtt.GetConfig 106 | ``` 107 | 108 | #### Exemple 5 : définir la configuration MQTT 109 | 110 | ```http 111 | POST /rpc 112 | Content-Type: application/json 113 | 114 | { 115 | "sn": "WOB1NHMAMXXXXX3", 116 | "method": "HA.Mqtt.SetConfig", 117 | "params": { 118 | "config": { 119 | "enable": true, 120 | "server": "192.168.50.48", 121 | "port":1883, 122 | "protocol":"mqtt", 123 | "username": "zendure", 124 | "password": "zendure" 125 | } 126 | } 127 | } 128 | ``` 129 | 130 | --- 131 | 132 | # 🛠️ Outils de développement 133 | 134 | ## Découverte mDNS au niveau système 135 | 136 | | OS | Commande exemple | Description | 137 | | ------- | ------------------------------------------------------------ | ----------------------------------------- | 138 | | Windows | `Get-Service \| Where-Object { $_.Name -like "*Bonjour*" }` | Vérifier le service Bonjour | 139 | | macOS | `dns-sd -B _zendure._tcp` | Parcourir les appareils Zendure | 140 | | Linux | `avahi-browse -r _zendure._tcp` | Découvrir les services `_zendure._tcp` | 141 | 142 | ## Exemples de code 143 | 144 | - [C](../examples/C/demo.c) 145 | - [C#](../examples/C%23/demo.cs) 146 | - [Java](../examples/Java/demo.java) 147 | - [JavaScript](../examples/JavaScript/demo.js) 148 | - [PHP](../examples/PHP/demo.php) 149 | - [Python](../examples/Python/demo.py) 150 | - [Test en ligne de commande](#test-rapide-en-ligne-de-commande) 151 | 152 | ### Test rapide en ligne de commande 153 | 154 | ```bash 155 | # Récupérer toutes les propriétés 156 | curl -X GET "http:///properties/report" 157 | 158 | # Vérifier l’état MQTT 159 | curl -X GET "http:///rpc?method=HA.Mqtt.GetStatus" 160 | 161 | # Définir la propriété acMode 162 | curl -X POST "http:///properties/write" \ 163 | -H "Content-Type: application/json" \ 164 | -d '{"sn": "votre_sn_appareil", "properties": { "acMode": 2 }}' 165 | ``` 166 | 167 | --- 168 | 169 | # 📚 Référence des propriétés 170 | 171 | Pour le détail des propriétés de chaque produit : 172 | [Documentation des propriétés SolarFlow](./fr_properties.md) 173 | 174 | --- 175 | -------------------------------------------------------------------------------- /docs/zh_properties.md: -------------------------------------------------------------------------------- 1 | 11 | 12 | # **SolarFlow 800** 13 | 14 | ## **电池包数据属性解析** 15 | 16 | | 属性 | 值类型 | 备注 | 17 | | ----------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | 18 | | packType | int | 无用 | 19 | | socLevel | int | 电池电量 | 20 | | state | int | 0:待机, 1:充电, 2:放电 | 21 | | power | int | 电池包功率 | 22 | | maxTemp | int | 电池最高温度 (maxTemp) 采用开尔文温度的 0.1 倍进行存储,计算摄氏温度 (°C) 的公式如下: float maxTemp_Celsius = (maxTemp - 2731) / 10.0; // 单位: °C | 23 | | totalVol | int | 总电压 | 24 | | batcur | int | 总电流(batcur)数据转换说明:batcur 原始数据为 16 位二补码,以 uint8_t[2] 存储。解析时需要将其转换为 有符号 16 位整数,再根据协议定义除以 10 得到实际电流值,单位为 A。计算公式如下:batcur_actual = ((int16_t)batcur) / 10.0; // 单位: A | 25 | | maxVol | int | 最高单体电压,数据以 0.01V 为单位存储,转换为实际电压的计算方式:maxVol / 100.0 (单位: V) | 26 | | minVol | int | 最低单体电压,数据以 0.01V 为单位存储,转换为实际电压的计算方式:minVol / 100.0 (单位: V) | 27 | | softVersion | int | 软件版本 | 28 | 29 | > **总电流(batcur)数据转换说明** 30 | 31 | > batcur** 原始数据为 ****16 位二补码**,以 uint8_t[2]** 存储。** 32 | 33 | > 解析时需要将其转换为 **有符号 16 位整数**,再根据协议定义除以 10 得到实际电流值,单位为 **A**。 34 | > 35 | > 36 | >> **总电流(batcur)数据转换说明** 37 | >> 38 | > 39 | >> batcur** 原始数据为 ****16 位二补码**,以 uint8_t[2]** 存储。** 40 | >> 41 | > 42 | >> 解析时需要将其转换为 **有符号 16 位整数**,再根据协议定义除以 10 得到实际电流值,单位为 **A**。 43 | >> 44 | >> 45 | 46 | > **总电流(batcur)数据转换说明** 47 | 48 | > batcur** 原始数据为 ****16 位二补码**,以 uint8_t[2]** 存储。** 49 | 50 | > 解析时需要将其转换为 **有符号 16 位整数**,再根据协议定义除以 10 得到实际电流值,单位为 **A**。 51 | > 52 | 53 | ## **设备数据属性解析-只读** 54 | 55 | | 属性 | 值类型 | 备注 | 56 | | --------------- | ------ | ---------------------------------- | 57 | | heatState | int | 0:未加热, 1:加热中 | 58 | | packInputPower | int | 电池包输入功率(放电) | 59 | | outputPackPower | int | 输出到电池包功率(充电) | 60 | | outputHomePower | int | 输出到家庭用电功率 | 61 | | remainOutTime | int | 剩余放电时长(单位:分钟) | 62 | | packState | int | 0:待机, 1:充电, 2:放电 | 63 | | packNum | int | 电池包数量 | 64 | | electricLevel | int | 电池包平均电量 | 65 | | gridInputPower | int | 电网输入功率 | 66 | | solarInputPower | int | 太阳能总输入功率 | 67 | | solarPower1 | int | 太阳能线路1输入功率 | 68 | | solarPower2 | int | 太阳能线路2输入功率 | 69 | | pass | int | 0:否, 1:是 | 70 | | reverseState | int | 0:否, 1:倒灌 | 71 | | socStatus | int | 0:否, 1:校准中 | 72 | | hyperTmp | int | 壳体温度 | 73 | | dcStatus | int | 0:停止, 1:电池输入, 2:电池输出 | 74 | | pvStatus | int | 0:停止, 1:运行 | 75 | | acStatus | int | 0:停止, 1:并离网运行, 2:充电运行 | 76 | | dataReady | int | 0:未准备好, 1:已准备好 | 77 | | gridState | int | 0:未接入, 1:已接入 | 78 | | FMVolt | int | 电压激活-电压值 | 79 | | socLimit | int | 0:正常状态, 1:充电截止, 2:放电截止 | 80 | 81 | ## **设备数据属性解析-读写** 82 | 83 | | 属性 | 值类型 | 备注 | 84 | | --------------- | ------ | ---------------------------------- | 85 | | writeRsp | 无 | 读写响应回复 | 86 | | acMode | int | 1:输入, 2:输出 | 87 | | inputLimit | int | AC充电功率限制 | 88 | | outputLimit | int | 输出功率限制 | 89 | | socSet | int | 700-1000: 70%-100% | 90 | | minSoc | int | 0-500: 0%-50% | 91 | | gridReverse | int | 0:未启用, 1:允许倒灌, 2:禁止倒灌 | 92 | | inverseMaxPower | int | 最大输出功率限制 | 93 | | gridStandard | int | 并网标准 0:德国 1:法国 2:奥地利 | 94 | -------------------------------------------------------------------------------- /docs/en_properties.md: -------------------------------------------------------------------------------- 1 | 11 | 12 | # **SolarFlow 800** 13 | 14 | ## **Battery Pack Data Properties** 15 | 16 | | Attribute | Data Type | Description | 17 | | ----------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | 18 | | packType | int | Not used | 19 | | socLevel | int | Battery charge level | 20 | | state | int | 0: Standby, 1: Charging, 2: Discharging | 21 | | power | int | Battery pack power | 22 | | maxTemp | int | Maximum battery temperature (maxTemp) is stored as one-tenth of the Kelvin temperature. The conversion formula to Celsius (°C) is:`float maxTemp_Celsius = (maxTemp - 2731) / 10.0; // Unit: °C` | 23 | | totalVol | int | Total voltage | 24 | | batcur | int | The raw batcur data is stored as a 16-bit two’s complement value in a uint8_t[2] array.During parsing, it needs to be converted into a signed 16-bit integer.According to the protocol definition, divide the value by 10 to obtain the actual current, in amperes (A). | 25 | | maxVol | int | Maximum cell voltage, stored in units of 0.01V. The conversion formula to actual voltage:`maxVol / 100.0` (Unit: V) | 26 | | minVol | int | Minimum cell voltage, stored in units of 0.01V. The conversion formula to actual voltage:`minVol / 100.0` (Unit: V) | 27 | | softVersion | int | Software version | 28 | 29 | **Battery Current (batcur) Data Conversion Description** 30 | 31 | The raw **batcur** data is stored as a **16-bit two’s complement** value in a **uint8_t[2]** array. 32 | 33 | During parsing, it needs to be converted into a **signed 16-bit integer**. 34 | 35 | According to the protocol definition, divide the value by **10** to obtain the actual current, in **amperes (A)**. 36 | 37 | ## **Device Data Properties - Read-Only** 38 | 39 | | Attribute | Data Type | Description | 40 | | --------------- | --------- | -------------------------------------------------------------------- | 41 | | heatState | int | 0: Not heating, 1: Heating | 42 | | packInputPower | int | Battery pack input power (discharging) | 43 | | outputPackPower | int | Output power to battery pack (charging) | 44 | | outputHomePower | int | Output power to home electricity | 45 | | remainOutTime | int | Remaining discharge time (unit: minutes) | 46 | | packState | int | 0: Standby, 1: Charging, 2: Discharging | 47 | | packNum | int | Number of battery packs | 48 | | electricLevel | int | Average battery pack charge level | 49 | | gridInputPower | int | Grid input power | 50 | | solarInputPower | int | Total solar input power | 51 | | solarPower1 | int | Solar line 1 input power | 52 | | solarPower2 | int | Solar line 2 input power | 53 | | pass | int | 0: No, 1: Yes | 54 | | reverseState | int | 0: No, 1: Reverse flow | 55 | | socStatus | int | 0: No, 1: Calibrating | 56 | | hyperTmp | int | Enclosure temperature | 57 | | dcStatus | int | 0: Stopped, 1: Battery input, 2: Battery output | 58 | | pvStatus | int | 0: Stopped, 1: Running | 59 | | acStatus | int | 0: Stopped, 1: Grid-connected operation, 2: Charging operation | 60 | | dataReady | int | 0: Not ready, 1: Ready | 61 | | gridState | int | 0: Not connected, 1: Connected | 62 | | FMVolt | int | Voltage activation - Voltage value | 63 | | socLimit | int | 0: Normal state, 1: Charge limit reached, 2: Discharge limit reached | 64 | 65 | ## **Device Data Properties - Read/Write** 66 | 67 | | Attribute | Data Type | Description | 68 | | --------------- | --------- | --------------------------------------------------------------- | 69 | | writeRsp | N/A | Read/write response acknowledgment | 70 | | acMode | int | 1: Input, 2: Output | 71 | | inputLimit | int | AC charging power limit | 72 | | outputLimit | int | Output power limit | 73 | | socSet | int | 700-1000: 70%-100% | 74 | | minSoc | int | 0-500: 0%-50% | 75 | | gridReverse | int | 0: Disabled, 1: Allowed reverse flow, 2: Forbidden reverse flow | 76 | | inverseMaxPower | int | Maximum output power limit | 77 | | gridStandard | int | Grid connection standard 0: Germany 1: France 2: Austria | 78 | | smartMode | int | 1: The setting parameter is not written to flash. After an unexpected power loss and restart, the device will use the value stored in flash. 0: The setting parameter is written to flash. | 79 | -------------------------------------------------------------------------------- /docs/openapi.yaml: -------------------------------------------------------------------------------- 1 | openapi: 3.0.0 2 | info: 3 | title: Device API 4 | description: API for managing device properties and HA MQTT integration. 5 | version: 1.0.0 6 | 7 | servers: 8 | - url: http:// 9 | description: The server IP where the API is hosted. 10 | 11 | paths: 12 | /properties/report: 13 | get: 14 | summary: Get device properties report 15 | operationId: getPropertiesReport 16 | responses: 17 | '200': 18 | description: A list of properties for the device. 19 | content: 20 | application/json: 21 | schema: 22 | type: object 23 | properties: 24 | timestamp: 25 | type: integer 26 | description: Timestamp of the report. 27 | messageId: 28 | type: integer 29 | description: Message identifier. 30 | sn: 31 | type: string 32 | description: Serial number of the device. 33 | version: 34 | type: integer 35 | description: Version of the report. 36 | product: 37 | type: string 38 | description: Product name. 39 | properties: 40 | type: object 41 | description: Device runtime properties. 42 | properties: 43 | heatState: 44 | type: integer 45 | description: '0: Not heating, 1: Heating.' 46 | packInputPower: 47 | type: integer 48 | outputPackPower: 49 | type: integer 50 | outputHomePower: 51 | type: integer 52 | remainOutTime: 53 | type: integer 54 | packState: 55 | type: integer 56 | description: '0: Standby, 1: Charging, 2: Discharging.' 57 | electricLevel: 58 | type: integer 59 | gridInputPower: 60 | type: integer 61 | solarInputPower: 62 | type: integer 63 | solarPower1: 64 | type: integer 65 | solarPower2: 66 | type: integer 67 | pass: 68 | type: integer 69 | reverseState: 70 | type: integer 71 | socStatus: 72 | type: integer 73 | hyperTmp: 74 | type: integer 75 | dcStatus: 76 | type: integer 77 | pvStatus: 78 | type: integer 79 | acStatus: 80 | type: integer 81 | dataReady: 82 | type: integer 83 | gridState: 84 | type: integer 85 | BatVolt: 86 | type: integer 87 | socLimit: 88 | type: integer 89 | writeRsp: 90 | type: integer 91 | acMode: 92 | type: integer 93 | inputLimit: 94 | type: integer 95 | outputLimit: 96 | type: integer 97 | socSet: 98 | type: integer 99 | minSoc: 100 | type: integer 101 | gridStandard: 102 | type: integer 103 | gridReverse: 104 | type: integer 105 | inverseMaxPower: 106 | type: integer 107 | lampSwitch: 108 | type: integer 109 | IOTState: 110 | type: integer 111 | factoryModeState: 112 | type: integer 113 | OTAState: 114 | type: integer 115 | LCNState: 116 | type: integer 117 | oldMode: 118 | type: integer 119 | VoltWakeup: 120 | type: integer 121 | ts: 122 | type: integer 123 | bindstate: 124 | type: integer 125 | tsZone: 126 | type: integer 127 | chargeMaxLimit: 128 | type: integer 129 | smartMode: 130 | type: integer 131 | rssi: 132 | type: integer 133 | is_error: 134 | type: integer 135 | packData: 136 | type: array 137 | items: 138 | type: object 139 | properties: 140 | sn: 141 | type: string 142 | packType: 143 | type: integer 144 | socLevel: 145 | type: integer 146 | state: 147 | type: integer 148 | power: 149 | type: integer 150 | maxTemp: 151 | type: integer 152 | totalVol: 153 | type: integer 154 | batcur: 155 | type: integer 156 | maxVol: 157 | type: integer 158 | minVol: 159 | type: integer 160 | softVersion: 161 | type: integer 162 | heatState: 163 | type: integer 164 | 165 | /properties/write: 166 | post: 167 | summary: Write device properties 168 | operationId: writeProperties 169 | requestBody: 170 | required: true 171 | content: 172 | application/json: 173 | schema: 174 | type: object 175 | properties: 176 | sn: 177 | type: string 178 | description: Serial number of the device. 179 | properties: 180 | type: object 181 | description: The properties to write to the device. 182 | properties: 183 | acMode: 184 | type: integer 185 | description: AC mode value for the device. 186 | responses: 187 | '200': 188 | description: Property successfully written to the device. 189 | '400': 190 | description: Bad request, invalid parameters or format. 191 | '401': 192 | description: Unauthorized, authentication failed. 193 | 194 | /rpc: 195 | get: 196 | summary: Get HA MQTT config or connection status 197 | description: | 198 | Use the `method` query parameter: 199 | - `HA.Mqtt.GetConfig`: Get MQTT configuration 200 | - `HA.Mqtt.GetStatus`: Get connection status 201 | operationId: getHaMqttInfo 202 | parameters: 203 | - name: method 204 | in: query 205 | required: true 206 | schema: 207 | type: string 208 | enum: [HA.Mqtt.GetConfig, HA.Mqtt.GetStatus] 209 | example: HA.Mqtt.GetConfig 210 | description: Method to execute 211 | responses: 212 | '200': 213 | description: Successful response 214 | content: 215 | application/json: 216 | schema: 217 | oneOf: 218 | - type: object 219 | description: Response from HA.Mqtt.GetConfig 220 | properties: 221 | result: 222 | type: boolean 223 | example: true 224 | data: 225 | type: object 226 | properties: 227 | enable: 228 | type: boolean 229 | example: true 230 | server: 231 | type: string 232 | example: mqtt://192.168.50.48:1883 233 | - type: object 234 | description: Response from HA.Mqtt.GetStatus 235 | properties: 236 | connected: 237 | type: boolean 238 | example: true 239 | 240 | post: 241 | summary: Set HA MQTT configuration 242 | operationId: setHaMqttConfig 243 | requestBody: 244 | required: true 245 | content: 246 | application/json: 247 | schema: 248 | type: object 249 | required: [sn, method, params] 250 | properties: 251 | sn: 252 | type: string 253 | example: WOB1NHMAMXXXXX3 254 | method: 255 | type: string 256 | enum: [HA.Mqtt.SetConfig] 257 | example: HA.Mqtt.SetConfig 258 | params: 259 | type: object 260 | required: [config] 261 | properties: 262 | config: 263 | type: object 264 | required: [enable, server] 265 | properties: 266 | enable: 267 | type: boolean 268 | example: true 269 | server: 270 | type: string 271 | example: mqtt://192.168.50.48:1883 272 | username: 273 | type: string 274 | example: zendure 275 | password: 276 | type: string 277 | example: zendure 278 | responses: 279 | '200': 280 | description: Successfully updated MQTT configuration 281 | content: 282 | application/json: 283 | schema: 284 | type: object 285 | properties: 286 | timestamp: 287 | type: integer 288 | format: int64 289 | example: 1749110672 290 | messageId: 291 | type: integer 292 | example: 1 293 | success: 294 | type: boolean 295 | example: true 296 | code: 297 | type: integer 298 | example: 200 299 | sn: 300 | type: string 301 | example: WOB1NHMAMXXXXX3 --------------------------------------------------------------------------------