您现在的位置是:网站首页> 开发积累

常用开放平台开发接口及库使用总结

摘要

常用开放平台开发接口及库使用总结


1.jpg



高德地图

物联网平台

OneNET和阿里云 / 腾讯云 IoT 对比


高德地图

点击进入高德地图开发平台

安装及使用实例



全程基于高德定位 SDK V9.0+(最新稳定版),适配 Android 6.0 + 动态权限、Android 10 + 后台定位、Android 12 + 精确 / 模糊定位,步骤清晰可落地,包含配置、编码、调试全流程。

一、前期准备:获取高德 Key(核心)

1 注册 / 登录高德地图开放平台,进入控制台→应用管理→创建新应用,填写应用名称、类型(选择「Android 端」)。

2 为应用添加 Key:选择「定位 SDK」,填写Android 包名(与项目build.gradle中applicationId完全一致)、SHA1 指纹(debug/release 环境需分别配置,测试阶段先配 debug)。

3 保存后得到唯一的高德 Key(如d48xxxxxxxxxxxxxxxxxxxxxx7e),后续配置全程用到。

快速获取 SHA1 指纹(Windows/macOS 通用)

Debug 环境:使用 Android Studio 默认 debug 签名,终端执行命令:

bash

运行

keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android

(macOS 直接执行,Windows 需先进入 JDK 的 bin 目录,~替换为C:\Users\你的用户名)

Release 环境:替换为自己的正式签名文件路径、别名、密码即可。

二、集成 SDK:两种方式(推荐远程依赖,无需手动导包)

方式 1:远程依赖(build.gradle,推荐)

1. 项目根目录build.gradle(Project 级)

添加高德 maven 仓库(若已有可忽略),在allprojects→repositories中配置:

gradle

allprojects {

    repositories {

        google()

        jcenter()

        // 高德maven仓库

        maven { url 'https://maven.aliyun.com/repository/public/' }

        maven { url 'https://developer.amap.com/maven/' }

    }

}

2. 模块目录build.gradle(Module 级,一般是 app)

添加依赖:在dependencies中加入定位 SDK 核心依赖(无需其他额外依赖):

gradle

dependencies {

    // 高德定位SDK V9.0+(最新稳定版,兼容Android 14)

    implementation 'com.amap.api:location:9.0.0'

}

配置编译参数:在android→defaultConfig中添加 NDK 架构(按需,至少保留armeabi-v7a/arm64-v8a):

gradle

android {

    compileSdk 34 // 适配自己的项目版本,最低支持21

    defaultConfig {

        applicationId "com.xxx.xxx" // 与高德Key的包名完全一致

        minSdk 21

        targetSdk 34

        // 高德定位SDK需要的NDK架构

        ndk {

            abiFilters "armeabi-v7a", "arm64-v8a"

        }

    }

    // 若使用Android Gradle Plugin 7.0+,需开启JDK8兼容

    compileOptions {

        sourceCompatibility JavaVersion.VERSION_1_8

        targetCompatibility JavaVersion.VERSION_1_8

    }

}

3. 同步 Gradle

点击 Android Studio 右上角「Sync Now」,等待 SDK 下载集成完成(若失败,检查网络或仓库地址)。

方式 2:手动集成(不推荐,适合无网络环境

1 从高德地图SDK下载页下载最新 SDK,解压得到amap_location_v9.x.x.jar和jniLibs文件夹。

2 将jar包复制到app/libs目录,右键→「Add as Library」添加依赖。

3 将jniLibs文件夹(包含各架构 so 文件)复制到app/src/main目录,与java/res同级。

三、配置 AndroidManifest.xml:权限 + Key + 服务

在app/src/main/AndroidManifest.xml中添加权限、高德 Key、定位服务,缺一不可,按位置粘贴即可。

1. 声明权限(分基础定位 / 后台定位,按需配置)

粘贴在<manifest>标签内、<application>标签外,Android 6.0 + 需动态申请,这里仅为清单声明

xml

<!-- 基础定位权限(必须):精确定位 -->

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

<!-- 粗略定位(备用,可选) -->

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

<!-- 网络权限(必须:基站/Wi-Fi定位需要) -->

<uses-permission android:name="android.permission.INTERNET" />

<!-- 网络状态(可选:判断网络是否可用,优化定位) -->

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

<!-- Wi-Fi状态(可选:Wi-Fi定位需要) -->

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />

<!-- 读取Wi-Fi MAC(可选:部分设备定位需要) -->

<uses-permission android:name="android.permission.READ_PHONE_STATE" />

<!-- 后台定位权限(Android 10+需要,若应用在后台也需定位则加) -->

<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />

<!-- 悬浮窗权限(Android 13+后台定位需要,可选) -->

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />


<!-- 声明定位硬件特性(可选,告诉应用市场该应用需要定位功能) -->

<uses-feature

    android:name="android.hardware.location"

    android:required="true" />

<uses-feature

    android:name="android.hardware.location.gps"

    android:required="false" />

2. 配置高德 Key(必须)

粘贴在<application>标签内,替换为自己的高德 Key:

xml

<meta-data

    android:name="com.amap.api.v2.apikey"

    android:value="你的高德Key" /> <!-- 核心,替换成第一步获取的Key -->

3. 声明定位服务(必须,高德 SDK 内部使用)

粘贴在<application>标签内,与上述 meta-data 同级:

xml

<!-- 高德定位服务,无需修改 -->

<service

    android:name="com.amap.api.location.APSService"

    android:exported="false" />

四、核心编码:Java 实现高德定位(Activity/Fragment 通用)

Activity为例,实现单次定位(最常用,如获取当前位置)和连续定位(如轨迹追踪),包含动态权限申请(Android 6.0 + 强制要求)、定位初始化、结果回调、资源释放(防止内存泄漏),代码可直接复制修改。

核心步骤:

1 动态申请定位权限(基础 / 后台);

2 初始化高德定位客户端AMapLocationClient;

3 配置定位参数AMapLocationClientOption;

4 设置定位回调AMapLocationListener,处理定位结果;

5 启动定位;

6 在生命周期(onDestroy)释放定位资源。

完整 Java 代码(Activity)

java

运行

package com.xxx.xxx; // 替换为自己的包名


import android.Manifest;

import android.content.pm.PackageManager;

import android.os.Bundle;

import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;

import androidx.core.app.ActivityCompat;

import androidx.core.content.ContextCompat;

import com.amap.api.location.AMapLocation;

import com.amap.api.location.AMapLocationClient;

import com.amap.api.location.AMapLocationClientOption;

import com.amap.api.location.AMapLocationListener;


public class LocationActivity extends AppCompatActivity {

    // 高德定位客户端(核心)

    public AMapLocationClient mLocationClient = null;

    // 高德定位参数配置

    public AMapLocationClientOption mLocationOption = null;

    // 定位权限请求码(自定义,建议100以上)

    private static final int LOCATION_PERMISSION_REQUEST_CODE = 101;

    // 后台定位权限请求码(Android 10+)

    private static final int BACKGROUND_LOCATION_REQUEST_CODE = 102;


    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_location); // 替换为自己的布局


        // 第一步:检查并申请定位权限

        checkLocationPermission();

    }


    /**

     * 检查定位权限:Android 6.0+动态申请

     */

    private void checkLocationPermission() {

        // 检查精确定位权限是否已授予

        if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)

                != PackageManager.PERMISSION_GRANTED) {

            // 未授予,申请基础定位权限(精确定位)

            ActivityCompat.requestPermissions(this,

                    new String[]{Manifest.permission.ACCESS_FINE_LOCATION},

                    LOCATION_PERMISSION_REQUEST_CODE);

        } else {

            // 已授予基础权限,若需要后台定位,检查后台权限(Android 10+)

            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {

                if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_BACKGROUND_LOCATION)

                        != PackageManager.PERMISSION_GRANTED) {

                    ActivityCompat.requestPermissions(this,

                            new String[]{Manifest.permission.ACCESS_BACKGROUND_LOCATION},

                            BACKGROUND_LOCATION_REQUEST_CODE);

                } else {

                    // 所有权限已授予,初始化定位

                    initLocation();

                }

            } else {

                // 低于Android 10,直接初始化定位

                initLocation();

            }

        }

    }


    /**

     * 第二步:初始化高德定位客户端+配置参数

     */

    private void initLocation() {

        try {

            // 初始化定位客户端

            mLocationClient = new AMapLocationClient(getApplicationContext());

            // 设置定位回调监听器

            mLocationClient.setLocationListener(mLocationListener);

            // 初始化定位参数

            mLocationOption = new AMapLocationClientOption();

            // 配置定位参数(重点,按需修改)

            // 1. 定位模式:高精度(GPS+网络+Wi-Fi)/仅网络/仅GPS,推荐高精度

            mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);

            // 2. 定位类型:单次定位(推荐)/连续定位,根据业务选择

            mLocationOption.setOnceLocation(true); // 单次定位(获取当前位置后停止)

            // 若要连续定位,注释上面一行,打开下面两行:

            // mLocationOption.setOnceLocation(false);

            // mLocationOption.setInterval(2000); // 连续定位间隔,单位ms,最小1000ms

            // 3. 是否返回地址信息(省/市/区/街道,推荐true)

            mLocationOption.setNeedAddress(true);

            // 4. 是否开启缓存(推荐true,优化首次定位速度)

            mLocationOption.setLocationCacheEnable(true);

            // 5. 定位超时时间(单位ms,默认30000,建议设为5000-10000)

            mLocationOption.setHttpTimeOut(8000);

            // 将配置参数设置给定位客户端

            mLocationClient.setLocationOption(mLocationOption);

            // 第三步:启动定位

            mLocationClient.startLocation();

        } catch (Exception e) {

            e.printStackTrace();

            Toast.makeText(this, "定位初始化失败:" + e.getMessage(), Toast.LENGTH_SHORT).show();

        }

    }


    /**

     * 第三步:定位回调监听器(处理定位结果/错误)

     */

    public AMapLocationListener mLocationListener = new AMapLocationListener() {

        @Override

        public void onLocationChanged(AMapLocation aMapLocation) {

            if (aMapLocation != null) {

                // 定位成功:aMapLocation.getErrorCode() == 0

                if (aMapLocation.getErrorCode() == 0) {

                    // 获取定位结果(核心字段,按需取值)

                    double latitude = aMapLocation.getLatitude(); // 纬度(GCJ02坐标系,高德专属)

                    double longitude = aMapLocation.getLongitude(); // 经度

                    float accuracy = aMapLocation.getAccuracy(); // 定位精度(米)

                    String address = aMapLocation.getAddress(); // 详细地址(如:北京市朝阳区XX路XX号)

                    String province = aMapLocation.getProvince(); // 省

                    String city = aMapLocation.getCity(); // 市

                    String district = aMapLocation.getDistrict(); // 区/县

                    String street = aMapLocation.getStreet(); // 街道

                    long time = aMapLocation.getTime(); // 定位时间(毫秒)

                    String locationType = aMapLocation.getLocationType(); // 定位类型(如GPS/基站/Wi-Fi)


                    // 打印结果(测试用,实际业务按需处理)

                    Toast.makeText(LocationActivity.this,

                            "定位成功:\n经纬度:" + longitude + "," + latitude +

                                    "\n地址:" + address, Toast.LENGTH_LONG).show();


                    // 单次定位:成功后停止定位(可选,SDK会自动停止)

                    if (mLocationClient != null) {

                        mLocationClient.stopLocation();

                    }


                } else {

                    // 定位失败:获取错误信息

                    String errorInfo = aMapLocation.getErrorInfo(); // 错误描述

                    int errorCode = aMapLocation.getErrorCode(); // 错误码

                    Toast.makeText(LocationActivity.this,

                            "定位失败:错误码" + errorCode + ",原因:" + errorInfo,

                            Toast.LENGTH_SHORT).show();

                    // 高德错误码查询:https://lbs.amap.com/api/android-location-sdk/guide/util/errorcode

                }

            } else {

                Toast.makeText(LocationActivity.this, "定位结果为空", Toast.LENGTH_SHORT).show();

            }

        }

    };


    /**

     * 权限申请结果回调

     */

    @Override

    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {

        super.onRequestPermissionsResult(requestCode, permissions, grantResults);

        if (requestCode == LOCATION_PERMISSION_REQUEST_CODE) {

            // 基础定位权限申请结果

            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                // 授予,继续检查后台定位权限(Android 10+)

                checkLocationPermission();

            } else {

                // 拒绝,提示用户开启权限

                Toast.makeText(this, "请开启定位权限,否则无法使用定位功能", Toast.LENGTH_SHORT).show();

            }

        } else if (requestCode == BACKGROUND_LOCATION_REQUEST_CODE) {

            // 后台定位权限申请结果

            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                initLocation();

            } else {

                // 拒绝,仅能前台定位,后台定位失效

                Toast.makeText(this, "后台定位权限未开启,应用后台将无法定位", Toast.LENGTH_SHORT).show();

                initLocation();

            }

        }

    }


    /**

     * 第四步:释放定位资源(必须,防止内存泄漏)

     * 在Activity/Fragment销毁时调用

     */

    @Override

    protected void onDestroy() {

        super.onDestroy();

        if (mLocationClient != null) {

            mLocationClient.onDestroy(); // 销毁定位客户端

            mLocationClient = null;

            mLocationOption = null;

        }

    }

}

五、关键配置说明(按需修改)

1. 定位模式选择

java

运行

// 高精度模式(推荐):GPS+基站+Wi-Fi,定位最快、精度最高

mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);

// 仅网络模式:无GPS时使用,精度约100-1000米,室内可用

// mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Battery_Saving);

// 仅GPS模式:精度最高(1-10米),但冷启动慢、室内无信号,适合户外

// mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Device_Sensors);

2. 单次 / 连续定位

单次定位:适合「获取当前位置」(如外卖、打车、签到),调用setOnceLocation(true),定位成功后 SDK 自动停止,也可手动调用stopLocation()。

连续定位:适合「轨迹追踪」(如运动、导航),调用setOnceLocation(false)+setInterval(2000)(间隔≥1000ms),后台定位需开启ACCESS_BACKGROUND_LOCATION权限。

3. 坐标系说明

高德定位 SDK 返回的是GCJ02(火星坐标系),与高德地图 / 导航 SDK 完全兼容,无需转换;若需转换为 WGS84(国际坐标系),需手动调用高德的坐标转换接口(商用需申请权限)。

六、常见问题与调试技巧

1. 定位失败:错误码排查(核心)

高德定位失败会返回错误码,可通过aMapLocation.getErrorCode()获取,对照高德错误码文档

排查,高频错误码:

1001:Key 错误 / 无效→检查 Key 是否正确、包名 / SHA1 是否与高德控制台一致;

1002:网络错误→检查网络是否可用、是否开启INTERNET权限;

1008:权限拒绝→检查动态权限是否申请成功、系统设置中是否开启 App 定位权限;

1012:GPS 未开启→提示用户在系统设置中开启 GPS;

1013:定位超时→延长HttpTimeOut、检查网络 / GPS 信号。

2. 调试注意事项

必须使用真机:模拟器无法定位(高德提供模拟器定位工具,不推荐);

开启系统定位:手机设置→「位置信息」→开启,选择「高精度模式」;

关闭省电模式:部分国产手机(小米 / 华为 / OPPO)的省电模式会限制定位,测试时关闭;

SHA1 / 包名一致:这是最常见的问题,确保build.gradle的applicationId、高德控制台的包名 / SHA1(debug/release)完全一致,大小写敏感。

3. 国产 ROM 适配(小米 / 华为 / OPPO/vivo)

部分国产手机会限制 App 的定位 / 后台权限,需在手机设置中手动开启:

1 开启「后台活动」/「允许后台运行」;

2 关闭「应用速冻」/「省电优化」;

3 加入「后台白名单」(如小米的「自启动管理」、华为的「应用启动管理」)。

七、进阶用法(可选)

1 后台连续定位:除了申请ACCESS_BACKGROUND_LOCATION权限,还可结合Service实现,将定位客户端初始化在 Service 中,保证应用后台时仍能定位;

2 定位缓存:开启setLocationCacheEnable(true),SDK 会缓存最近一次定位结果,无网络时可快速获取;

3 地址解析:若仅需经纬度转地址,可使用高德地理编码 / 逆地理编码 SDK,与定位 SDK 配合使用;

4 多进程适配:若 App 使用多进程,需在AMapLocationClient初始化时指定进程,或在 Manifest 中为定位服务配置android:process。

八、官方资源

高德定位SDK官方文档

高德定位SDK Memo

高德错误码查询

高德Key 申请与配置教程

快速验证

按上述步骤配置后,运行真机,若弹出权限申请弹窗,允许后能看到「定位成功」的 Toast,显示经纬度和详细地址,即接入成功。

如果需要Service 版后台连续定位代码、经纬度转 WGS84 坐标系代码,或排查具体定位失败问题(如错误码 1001/1008),可以告诉我,我会补充对应的代码和解决方案。


OneNET和阿里云 / 腾讯云 IoT 对比

点击查看OneNET官方平台介绍

介绍

每日 300 万次免费LBS 基站定位

EDP协议接入这个EDP有啥优势

OneNET Wifi 定位


OneNET:50 台永久免费,国内 NB‑IoT 最稳,文档中文,门槛最低,,

阿里云:免费额度少,超过后贵

腾讯云:免费也少,生态强但贵


2024 年后 OneNET 引入 设备激活码 机制:

新设备必须绑激活码才能上线

免费用户每月送一定量激活码(够 50 台)

超过 50 台,就要买激活码(按 “活跃设备数” 计费)

OneNET:

  • 设备 ≤50 台:完全免费
  • 只用 MQTT 上报 + HTTP 查数据:一分钱不花
  • 不用 OTA、不用 MQ 消息队列、不用高级 View:永远免费

核心能力(你最关心的)

1)多协议接入(设备端)

  • MQTT(最常用,ESP32/STM32 / 树莓派首选)
  • NB‑IoT(LwM2M/CoAP):移动物联卡超低功耗
  • EDP(OneNET 私有)、Modbus、HTTP、TCP 透传
  • C/Python/Java/Node.js SDK,直接复制 Demo 就能跑


2)设备管理

  • 创产品→创设备→拿 设备 ID/API‑Key(鉴权用)
  • 上下线状态、数据点存储、历史查询、远程命令下发OneNET
  • OTA 远程升级(固件 / 应用)OneNET

3)数据与应用

  • 时序数据库存传感器数据(温湿度、电压、GPS…)
  • View 可视化:拖拽做仪表盘、折线图、告警OneNET
  • API 全开放:HTTP/HTTPS,可对接自有服务器、APP、小程序
  • 规则引擎:数据超限自动发告警(短信 / HTTP 回调)


4)免费额度(个人 / 创客够用)

  • 免费版:100 台设备 + 每月 10 万次 API 调用
  • 数据点存储、基础可视化、MQTT 连接都免费

✅ 典型用法(你之前 curl 就属于这类)

  1. 设备(如 ESP32)用 MQTT 往 OneNET 发数据(温度、开关状态)
  2. OneNET 存数据,你用 HTTP API 拉数据 / 下发指令(就是你那条 curl -H "X-API-Key"
  3. 前端用 View 做监控面板,或对接自己后台

✅ 和你之前命令的关系

你这条:

curl -X GET http://www.1xn1.com:1235/api/terminal/.../params/query \

  -H "X-API-Key: your-secret-api-key-123"


OneNET 接入代码

一、Go 语言 MQTT 接入(主流方案)

依赖

bash

运行

go get github.com/eclipse/paho.mqtt.golang

完整代码

go

运行

package main


import (

"fmt"

"log"

"time"


mqtt "github.com/eclipse/paho.mqtt.golang"

)


const (

// OneNET MQTT 服务器

mqttBroker = "tcp://mqtt.heclouds.com:1883"

// 产品ID

productID  = "你的产品ID"

// 设备名称

deviceName = "你的设备名称"

// 设备鉴权信息

deviceKey  = "你的设备APIKey"

)


var client mqtt.Client


func onConnectHandler(client mqtt.Client) {

fmt.Println("成功连接OneNET MQTT服务器")

}


func initClient() {

opts := mqtt.NewClientOptions()

opts.AddBroker(mqttBroker)

// 客户端ID格式:产品ID&设备名称

opts.SetClientID(fmt.Sprintf("%s&%s", productID, deviceName))

opts.SetUsername(productID)

opts.SetPassword(deviceKey)

opts.SetConnectTimeout(5 * time.Second)

opts.OnConnect = onConnectHandler


client = mqtt.NewClient(opts)

if token := client.Connect(); token.Wait() && token.Error() != nil {

log.Fatal("连接失败:", token.Error())

}

}


// 上传遥测数据

func uploadData() {

// OneNET 标准上报主题

topic := fmt.Sprintf("devices/%s/datapoints", deviceName)

// 上报JSON数据

payload := `{"id":1,"dp":{"temp":{"v":25.5},"hum":{"v":60}}}`


token := client.Publish(topic, 0, false, payload)

token.Wait()

fmt.Println("数据上报完成")

}


func main() {

initClient()

// 循环上报

for {

uploadData()

time.Sleep(3 * time.Second)

}

}

二、C# .NET MQTT 接入

NuGet 安装

plaintext

Install-Package MQTTnet

完整代码

csharp

运行

using System;

using System.Threading.Tasks;

using MQTTnet;

using MQTTnet.Client;


namespace OneNetDemo

{

    class Program

    {

        static async Task Main(string[] args)

        {

            string broker = "mqtt.heclouds.com";

            int port = 1883;

            string productId = "你的产品ID";

            string deviceName = "你的设备名";

            string deviceKey = "你的设备密钥";


            var factory = new MqttFactory();

            var mqttClient = factory.CreateMqttClient();


            var options = new MqttClientOptionsBuilder()

                .WithTcpServer(broker, port)

                .WithClientId($"{productId}&{deviceName}")

                .WithCredentials(productId, deviceKey)

                .Build();


            // 连接

            await mqttClient.ConnectAsync(options);

            Console.WriteLine("连接OneNET成功");


            // 上报主题

            string topic = $"devices/{deviceName}/datapoints";

            string data = @"{""id"":1,""dp"":{""temp"":{""v"":26.0}}}";


            // 发布数据

            var msg = new MqttApplicationMessageBuilder()

                .WithTopic(topic)

                .WithPayload(data)

                .Build();


            await mqttClient.PublishAsync(msg);

            Console.WriteLine("数据发送成功");


            await Task.Delay(-1);

        }

    }

}

三、HTTP API 查询设备数据(通用,对应你之前 curl)

Go HTTP 请求

go

运行

package main


import (

"fmt"

"io"

"net/http"

)


func main() {

url := "http://api.heclouds.com/devices/设备ID/datapoints"

req, _ := http.NewRequest("GET", url, nil)

// OneNET 请求头

req.Header.Set("api-key", "你的Master-APIKey")


client := &http.Client{}

resp, _ := client.Do(req)

defer resp.Body.Close()

res, _ := io.ReadAll(resp.Body)

fmt.Println(string(res))

}

C# HTTP 请求

csharp

运行

using System.Net.Http;


class HttpDemo

{

    static async void GetData()

    {

        using var client = new HttpClient();

        client.DefaultRequestHeaders.Add("api-key", "你的主API密钥");

        var res = await client.GetStringAsync("http://api.heclouds.com/devices/设备ID/datapoints");

        Console.WriteLine(res);

    }

}

配置填写说明

后台获取:产品 ID、设备名称、设备密钥(设备接入密钥)

HTTP 接口用:Master APIKey(产品全局密钥)

数据点 temp/hum 改成你自己平台定义的标识符即可

支持 TCP 透传、指令下发、离线缓存全适配


OneNET每日 300 万次免费LBS 基站定位

一、LBS 是什么(一句话)

不用 GPS,只用 2G/3G/4G/NB‑IoT 模组读到的基站信息(LAC+CID),上传 OneNET,平台返回经纬度。

精度:几百米~1km(郊区更差)

功耗:极低(不用 GPS 搜星)

费用:每日 300 万次免费,超出才计费


二、开通 & 配置(必须做)

1. 开通 LBS 服务

OneNET 后台 → 增值服务 → 基站定位 → 立即开通

1.png


2. 产品加 “基站定位” 功能点

设备接入 → 产品管理 → 产品详情 → 添加系统功能点 → 基站定位(数组类型,最多 3 个基站)

1.png


3. 数据流名固定

必须往 $OneNET_LBS 这个数据流上报基站信息

三、基站信息字段(上报格式)

单基站(最常用)

json

{

  "mcc": 460,

  "mnc": 0,

  "lac": 12345,

  "cid": 67890,

  "networkType": 5

}

mcc=460(中国固定)

mnc=0 移动 / 1 联通 / 2 电信

lac、cid:模组 AT 指令读到的小区码、基站码(必传)

networkType:1=GSM,5=LTE(4G)

多基站(精度略高,最多 3 个)

json

[

  {"mcc":460,"mnc":0,"lac":12345,"cid":67890},

  {"mcc":460,"mnc":0,"lac":12346,"cid":67891}

]

四、模组怎么读基站信息(AT 指令)

以 移远 / 中移 NB‑IoT/4G 模组为例:

bash

运行

# 读当前基站

AT+CREG?

# 读邻区基站(可选)

AT+CGMR

拿到 LAC、CID 后,打包成上面 JSON 上报即可。

五、Go 代码(MQTT 上报基站信息)

go

运行

package main


import (

"fmt"

"log"

"time"


mqtt "github.com/eclipse/paho.mqtt.golang"

)


const (

mqttBroker = "tcp://mqtt.heclouds.com:1883"

productID  = "你的产品ID"

deviceName = "你的设备名"

deviceKey  = "你的设备APIKey"

)


func main() {

opts := mqtt.NewClientOptions()

opts.AddBroker(mqttBroker)

opts.SetClientID(productID + "&" + deviceName)

opts.SetUsername(productID)

opts.SetPassword(deviceKey)


client := mqtt.NewClient(opts)

if token := client.Connect(); token.Wait() && token.Error() != nil {

log.Fatal(token.Error())

}


// 上报主题:固定 $OneNET_LBS

topic := fmt.Sprintf("devices/%s/datapoints", deviceName)

payload := `{

"id":1,

"dp":{

"$OneNET_LBS":{

"mcc":460,

"mnc":0,

"lac":12345,

"cid":67890,

"networkType":5

}

}

}`


token := client.Publish(topic, 0, false, payload)

token.Wait()

fmt.Println("LBS基站信息上报成功")


time.Sleep(3 * time.Second)

}

六、C# 代码(MQTT 上报,MQTTnet)

csharp

运行

using System;

using System.Threading.Tasks;

using MQTTnet;

using MQTTnet.Client;


class LbsDemo

{

    static async Task Main()

    {

        string broker = "mqtt.heclouds.com";

        string productId = "你的产品ID";

        string deviceName = "你的设备名";

        string deviceKey = "你的设备APIKey";


        var factory = new MqttFactory();

        var client = factory.CreateMqttClient();


        var options = new MqttClientOptionsBuilder()

            .WithTcpServer(broker, 1883)

            .WithClientId($"{productId}&{deviceName}")

            .WithCredentials(productId, deviceKey)

            .Build();


        await client.ConnectAsync(options);


        string topic = $"devices/{deviceName}/datapoints";

        string payload = @"{""id"":1,""dp"":{""$OneNET_LBS"":{""mcc"":460,""mnc"":0,""lac"":12345,""cid"":67890,""networkType"":5}}}";


        var msg = new MqttApplicationMessageBuilder()

            .WithTopic(topic)

            .WithPayload(payload)

            .Build();


        await client.PublishAsync(msg);

        Console.WriteLine("LBS上报成功");

    }

}

七、查询经纬度(HTTP API)

上报后,用 Master APIKey 查位置:

bash

运行

# 最新位置

curl -H "api-key: 你的Master-APIKey" \

"http://api.heclouds.com/devices/设备ID/lbs"

返回:

json

{

  "lon": 116.403874,

  "lat": 39.914885,

  "addr": "北京市东城区..."

}

查历史位置:

一、两个接口区别(关键)

1.查最新位置(你用的)

plaintext

GET /devices/{device_id}/lbs

只返回最近一次定位

无历史、无轨迹

2.查历史轨迹(真正的历史位置)

plaintext

GET /lbs?action=getTrail&version=1&...

按时间范围返回多条历史经纬度

带时间戳、可分页、可排序

3.通用数据点历史($OneNET_LBS 原始记录)

plaintext

GET /devices/{device_id}/datapoints?stream_id=$OneNET_LBS&...

查基站原始上报记录(含 LAC/CID)

也会附带平台算出的经纬度

二、历史轨迹 API(getTrail)完整用法(直接能用)

1)HTTP 地址(openapi,不是 api.heclouds.com)

plaintext

GET https://openapi.heclouds.com/lbs

2)必须参数

plaintext

action=getTrail

version=1

product_id=你的产品ID

device_name=你的设备名

3)可选时间 / 分页

plaintext

start=2026-05-10T00:00:00.000

end=2026-05-18T12:00:00.000

page=1

per_page=50

sort=ASC

```{insert\_element\_2\_}


### 4)curl 示例(直接复制,改参数即可)

```bash

curl -H "authorization: 你的Master-APIKey" \

"https://openapi.heclouds.com/lbs?action=getTrail&version=1&product_id=ABCDEFG&device_name=dev01&start=2026-05-10T00:00:00.000&end=2026-05-18T12:00:00.000"

5)返回格式(含时间 + 经纬度 + 地址)

json

{

  "data": [

    {

      "lon": 116.403874,

      "lat": 39.914885,

      "addr": "北京市东城区...",

      "time": "2026-05-17T08:22:15.123"

    },

    {

      "lon": 116.404001,

      "lat": 39.915002,

      "addr": "北京市东城区...",

      "time": "2026-05-17T08:25:42.456"

    }

  ],

  "total": 28,

  "page": 1,

  "per_page": 50

}

三、Go 示例(历史轨迹查询)

go

运行

package main


import (

"fmt"

"io/ioutil"

"net/http"

"time"

)


func main() {

masterKey := "你的Master-APIKey"

productID := "你的产品ID"

deviceName := "你的设备名"

start := "2026-05-10T00:00:00.000"

end := "2026-05-18T12:00:00.000"


url := fmt.Sprintf(

"https://openapi.heclouds.com/lbs?action=getTrail&version=1&product_id=%s&device_name=%s&start=%s&end=%s",

productID, deviceName, start, end,

)


req, _ := http.NewRequest("GET", url, nil)

req.Header.Set("authorization", masterKey)


client := &http.Client{Timeout: 10 * time.Second}

resp, err := client.Do(req)

if err != nil {

panic(err)

}

defer resp.Body.Close()


b, _ := ioutil.ReadAll(resp.Body)

fmt.Println(string(b))

}

四、C# 示例(历史轨迹查询)

csharp

运行

using System;

using System.Net.Http;

using System.Net.Http.Headers;


class LbsHistory

{

    static async System.Threading.Tasks.Task Main()

    {

        string masterKey = "你的Master-APIKey";

        string productId = "你的产品ID";

        string deviceName = "你的设备名";

        string start = "2026-05-10T00:00:00.000";

        string end = "2026-05-18T12:00:00.000";


        string url = $"https://openapi.heclouds.com/lbs?action=getTrail&version=1&product_id={productId}&device_name={deviceName}&start={start}&end={end}";


        using (var client = new HttpClient())

        {

            client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(masterKey);

            var resp = await client.GetAsync(url);

            string json = await resp.Content.ReadAsStringAsync();

            Console.WriteLine(json);

        }

    }

}

五、数据保留多久(重要)

LBS 定位轨迹:默认保留 30 天(免费版)

$OneNET_LBS 数据点:免费版 7 天,付费可 1 年 +

超过时间会被清理,查不到更早数据

六、常见坑

❌ 用 api.heclouds.com 查历史:必须用 openapi.heclouds.com

❌ 用 Device-APIKey 查历史:必须用 Master-APIKey

❌ 时间格式不对:必须 yyyy-MM-ddTHH:mm:ss.fff

❌ 只传 device_id:getTrail 要 product_id + device_name

七、一句话总结

/lbs → 最新 1 条

/lbs?action=getTrail → 历史轨迹(时间范围)

/datapoints?stream_id=$OneNET_LBS → 原始基站上报 + 经纬度历史



八、免费额度 & 收费(2026 最新)

✅ 每日 300 万次定位免费

✅ 单设备每日上报几十次完全免费

⚠️ 超出:14.5 元 / 万次(包年)

九、常见坑

数据流名必须是 $OneNET_LBS,写错不计算位置

mcc 必须 460(中国),否则报错

只支持移动 / 联通 / 电信基站,不支持 Wi‑Fi

精度几百米,不能替代 GPS


EDP协议接入这个EDP有啥优势

EDP 是什么(一句话)

EDP = Enhanced Device Protocol,OneNET 自己定制的、基于 TCP 的二进制长连接协议,专为 OneNET 优化,比 MQTT 更轻、比 HTTP 更适合长连接控制

EDP 的 6 个核心优势(工程最看重)

1. 比 MQTT 更轻量、包更小(省流量 / 省电)

MQTT 头长、有 Topic、QoS、订阅等冗余字段

EDP 固定 8 字节头 + 二进制格式,报文极小

适合 MCU/STM32/ESP8266/4G 模组等资源受限设备

2. 原生长连接 + 心跳保活(不掉线、实时性强)

基于 TCP,一次连接永久在线(靠心跳)

平台主动下发命令毫秒级到达

支持 离线消息缓存(设备上线后补发)

HTTP 每次都要握手,MQTT 重连开销大

3. OneNET 平台深度集成(功能全开、最稳)

LBS 基站定位原生支持(你现在用的功能)

数据点自动存入平台数据库(直接查历史)

透传、转发、命令下发、固件升级全支持

不用自己解析 JSON,直接二进制上报

4. 简单到极致(接入代码极少、调试快)

登录:设备 ID + 密钥,一步认证

上报:直接发 “数据流 + 值”,不用 Topic

下发:平台直接推,不用订阅

官方有 C/Go/C#/Python SDK,直接复制就能跑

5. 安全内置(加密 + 校验,防篡改)

支持 AES 加密传输(可选)

每个包带 校验和,防丢包 / 错包

平台严格鉴权,设备不能伪造身份

6. 端到端转发(设备→设备直接通信)

同一产品下,设备 A 可直接发数据给设备 B

平台中转,不用自己做服务器转发

MQTT 也能做,但 EDP 配置更简单、延迟更低


什么时候必须用 EDP?

你在用 OneNET + LBS 基站定位(原生支持,最稳)

设备是 MCU / 低功耗模组(省流量、省电)

需要 实时下发命令 / 远程控制(开关、调光、启停)

不想写复杂 MQTT 逻辑、想快速上线


OneNET EDP 协议接入示例

EDP 基于原生 TCP 长连接,协议极简,包含:登录鉴权、心跳保活、数据上报、平台指令接收

一、EDP 核心通信地址

plaintext

TCP地址:183.230.40.39

端口:8087

二、C# 完整 EDP 客户端代码

环境

.NET Framework /.NET Core 通用,纯原生 Socket 无第三方库

csharp

运行

using System;

using System.IO;

using System.Net.Sockets;

using System.Text;

using System.Threading;


namespace OneNetEDP

{

    class EdpClient

    {

        private TcpClient _client;

        private NetworkStream _stream;

        private readonly string _deviceId = "填写你的设备ID";

        private readonly string _deviceKey = "填写设备接入密钥";

        private bool _isLogin = false;


        // 启动连接

        public void StartConnect()

        {

            try

            {

                _client = new TcpClient();

                Console.WriteLine("正在连接OneNET EDP服务器...");

                _client.Connect("183.230.40.39", 8087);

                _stream = _client.GetStream();

                Console.WriteLine("连接成功,发起登录鉴权");


                // 发送EDP登录包

                SendLoginPacket();

                // 开启接收线程

                new Thread(RecvMsg).Start();

                // 定时心跳

                new Thread(HeartBeatLoop).Start();

            }

            catch (Exception ex)

            {

                Console.WriteLine("连接失败:" + ex.Message);

            }

        }


        // 构造EDP登录数据包

        private void SendLoginPacket()

        {

            MemoryStream ms = new MemoryStream();

            BinaryWriter bw = new BinaryWriter(ms);

            // EDP协议头 固定2字节 0x01 0x00

            bw.Write((byte)0x01);

            bw.Write((byte)0x00);


            byte[] devIdBuf = Encoding.ASCII.GetBytes(_deviceId);

            // 设备ID长度+内容

            bw.Write((ushort)devIdBuf.Length);

            bw.Write(devIdBuf);


            byte[] keyBuf = Encoding.ASCII.GetBytes(_deviceKey);

            // 密钥长度+内容

            bw.Write((ushort)keyBuf.Length);

            bw.Write(keyBuf);


            byte[] loginData = ms.ToArray();

            SendData(loginData);

        }


        // 发送EDP心跳包

        private void SendHeartBeat()

        {

            byte[] heart = new byte[] { 0x02, 0x00, 0x00 };

            SendData(heart);

        }


        // 上报数值型数据

        public void UploadData(string streamName, float value)

        {

            if (!_isLogin) return;

            MemoryStream ms = new MemoryStream();

            BinaryWriter bw = new BinaryWriter(ms);

            // 数据上报指令头

            bw.Write((byte)0x03);

            bw.Write((byte)0x00);


            byte[] nameBuf = Encoding.ASCII.GetBytes(streamName);

            bw.Write((ushort)nameBuf.Length);

            bw.Write(nameBuf);


            // 浮点数据

            bw.Write(value);

            byte[] sendBuf = ms.ToArray();

            SendData(sendBuf);

            Console.WriteLine($"上报数据流:{streamName} 数值:{value}");

        }


        // 底层发送

        private void SendData(byte[] data)

        {

            try

            {

                _stream.Write(data, 0, data.Length);

                _stream.Flush();

            }

            catch

            {

                _isLogin = false;

            }

        }


        // 循环接收平台下发数据

        private void RecvMsg()

        {

            byte[] buffer = new byte[1024];

            while (true)

            {

                try

                {

                    int len = _stream.Read(buffer, 0, buffer.Length);

                    if (len <= 0) break;


                    // 登录成功应答

                    if (buffer[0] == 0x81)

                    {

                        _isLogin = true;

                        Console.WriteLine("EDP登录OneNET成功!");

                    }

                    // 平台下发控制指令

                    else if (buffer[0] == 0x84)

                    {

                        Console.WriteLine("收到平台下发远程指令");

                    }

                }

                catch

                {

                    break;

                }

            }

        }


        // 30秒一次心跳保活

        private void HeartBeatLoop()

        {

            while (true)

            {

                Thread.Sleep(30000);

                if (_isLogin)

                {

                    SendHeartBeat();

                    Console.WriteLine("已发送EDP心跳包");

                }

            }

        }

    }


    class Program

    {

        static void Main(string[] args)

        {

            EdpClient edp = new EdpClient();

            edp.StartConnect();


            // 循环模拟上报数据

            while (true)

            {

                edp.UploadData("temp", (float)new Random().Next(20, 35));

                Thread.Sleep(5000);

            }

        }

    }

}

三、Go 语言 EDP 极简客户端

go

运行

package main


import (

"encoding/binary"

"fmt"

"net"

"time"

)


const (

edpAddr  = "183.230.40.39:8087"

deviceID = "你的设备ID"

deviceKey = "你的设备密钥"

)


var conn net.Conn

var isLogin bool


// 连接服务器

func connectEDP() error {

conn, _ = net.Dial("tcp", edpAddr)

fmt.Println("EDP连接成功")

sendLogin()

go recvLoop()

go heartBeatLoop()

return nil

}


// 发送登录包

func sendLogin() {

buf := make([]byte, 0, 128)

// 协议头 01 00

buf = append(buf, 0x01, 0x00)


// 设备ID

idBs := []byte(deviceID)

buf = binary.BigEndian.AppendUint16(buf, uint16(len(idBs)))

buf = append(buf, idBs...)


// 设备密钥

keyBs := []byte(deviceKey)

buf = binary.BigEndian.AppendUint16(buf, uint16(len(keyBs)))

buf = append(buf, keyBs...)


conn.Write(buf)

}


// 发送心跳

func sendHeart() {

conn.Write([]byte{0x02, 0x00, 0x00})

}


// 上报数据

func uploadData(stream string, val float32) {

if !isLogin {

return

}

buf := make([]byte, 0, 64)

buf = append(buf, 0x03, 0x00)

nameBs := []byte(stream)

buf = binary.BigEndian.AppendUint16(buf, uint16(len(nameBs)))

buf = append(buf, nameBs...)


// 写入浮点值

tmp := make([]byte, 4)

binary.LittleEndian.PutUint32(tmp, uint32(val))

buf = append(buf, tmp...)

conn.Write(buf)

fmt.Printf("上报 %s = %.2f\n", stream, val)

}


// 接收数据

func recvLoop() {

readBuf := make([]byte, 1024)

for {

n, _ := conn.Read(readBuf)

if n == 0 {

break

}

if readBuf[0] == 0x81 {

isLogin = true

fmt.Println("EDP登录鉴权成功")

}

}

}


// 心跳协程

func heartBeatLoop() {

for range time.Tick(30 * time.Second) {

if isLogin {

sendHeart()

}

}

}


func main() {

connectEDP()

// 定时上报

for range time.Tick(5 * time.Second) {

uploadData("hum", 55.2)

}

}

四、EDP 常用指令码速查表

表格

指令码 功能

0x01 设备登录

0x02 心跳包

0x03 上传普通数据点

0x04 上传 LBS 基站定位数据

0x81 平台返回登录成功

0x84 平台下发远程控制指令

五、使用要点

设备 ID、设备密钥在 OneNET 设备详情页获取

心跳30 秒发送一次,超时会被平台踢下线

数据流名称必须和平台产品定义一致

纯二进制协议,流量极小,4G/NB-IoT 模组首选

支持离线缓存,设备断线重连后自动补发平台下发指令

需要我给你加EDP 上报 LBS 基站定位数据包代码吗?


OneNET EDP 协议上报 LBS 基站定位

协议规则

上报 LBS 指令头:0x04 0x00

固定字段:mcc/mnc/lac/cid/网络类型

服务端 TCP:183.230.40.39:8087

一、C# 新增 LBS 上报方法

直接追加到上面EdpClient类里

csharp

运行

/// <summary>

/// EDP上报LBS基站定位

/// </summary>

/// <param name="mcc">国家码 中国固定460</param>

/// <param name="mnc">运营商 0移动 1联通 2电信</param>

/// <param name="lac">位置区码</param>

/// <param name="cid">小区基站ID</param>

/// <param name="netType">网络类型 5=4G</param>

public void UploadLbsData(ushort mcc, byte mnc, ushort lac, uint cid, byte netType = 5)

{

    if (!_isLogin) return;

    MemoryStream ms = new MemoryStream();

    BinaryWriter bw = new BinaryWriter(ms);


    // EDP LBS上报固定包头

    bw.Write((byte)0x04);

    bw.Write((byte)0x00);


    // 按协议顺序写入字段

    bw.Write(mcc);      // 2字节

    bw.Write(mnc);      // 1字节

    bw.Write(lac);      // 2字节

    bw.Write(cid);      // 4字节

    bw.Write(netType);  // 1字节


    byte[] lbsPacket = ms.ToArray();

    SendData(lbsPacket);

    Console.WriteLine($"EDP上报LBS成功:LAC={lac} CID={cid}");

}

调用示例

csharp

运行

// 模拟4G移动基站数据

edp.UploadLbsData(460, 0, 12345, 67890123, 5);

二、Go 新增 LBS 上报函数

追加到 Go 代码中

go

运行

// EDP上报LBS基站定位

func uploadLBS(mcc uint16, mnc uint8, lac uint16, cid uint32, netType uint8) {

if !isLogin {

return

}

buf := make([]byte, 0, 32)

// LBS上报指令头

buf = append(buf, 0x04, 0x00)


// 大端序写入字段

buf = binary.BigEndian.AppendUint16(buf, mcc)

buf = append(buf, mnc)

buf = binary.BigEndian.AppendUint16(buf, lac)

buf = binary.BigEndian.AppendUint32(buf, cid)

buf = append(buf, netType)


_, _ = conn.Write(buf)

fmt.Printf("LBS上报完成 mcc:%d lac:%d cid:%d\n", mcc, lac, cid)

}

调用示例

go

运行

// 定时上报定位

uploadLBS(460,0,12345,67890123,5)

三、EDP-LBS 数据包完整结构

表格

偏移 长度 含义 说明

0 1 命令码 0x04 = LBS 定位上报

1 1 保留位 固定 0x00

2 2 MCC 中国固定460

4 1 MNC 0 移动 / 1 联通 / 2 电信

5 2 LAC 位置区域码

7 4 CID 基站小区编号

11 1 网络类型 5=LTE(4G)

四、配套说明

上报成功后,平台自动解析经纬度,无需额外处理

可用接口 GET /devices/设备ID/lbs 直接读取定位结果

心跳依旧 30s 一次,防止断连

NB-IoT/4G 模组读取 AT 指令拿到LAC/CID直接填入即可

纯二进制报文,比 MQTT 体积小一半,极致省流量


OneNET Wifi 定位

下面直接给你 OneNET WiFi 定位 完整开通 + 上报 + 查询全流程(EDP/HTTP/MQTT 都能用),2026-05-18 最新规则,照着就能跑。

一、WiFi 定位原理(一句话)

设备扫描周边 WiFi(BSSID+RSSI)→ 上传到 OneNET 固定数据流 $OneNET_LBS_WIFI → 平台返回经纬度(精度 10–50m,室内远好于基站)。

二、平台开通(必须先做)

1. 入口

登录 OneNET → 开发者中心 → 全部产品 → 位置能力 LBS → WiFi 定位。

1.png


2. 开通步骤

选择你的产品(WiFi 定位按产品开通)

点击 立即开通(有每日免费额度,够用)

开通成功后,该产品下所有设备都能用 WiFi 定位

1.png1.png




三、设备端:扫描周边 WiFi

1. ESP8266/ESP32(AT 指令)

plaintext

AT+CWLAP   // 扫描附近WiFi,返回:

// +CWLAP:(3,"TP-LINK_123",-65,"AA:BB:CC:DD:EE:01",1,4,0)

// 关键:mac=AA:BB:CC:DD:EE:01,rssi=-65

至少扫 3 个 WiFi,越多越准。

2. 其他 WiFi 模组

用对应扫描指令,最终拿到:

mac:BSSID(WiFi 网卡地址,AA:BB:CC:DD:EE:FF 格式)

rssi:信号强度(-30 ~ -90,绝对值越小越强)

四、上报格式(核心!EDP/HTTP/MQTT 通用)

数据流名固定:$OneNET_LBS_WIFI数据点 value = JSON 字符串

✅ 标准 JSON 模板(直接复制)

json

{

  "mcc": 460,

  "mnc": 0,

  "bssids": [

    {"mac": "AA:BB:CC:DD:EE:01", "rssi": -65},

    {"mac": "AA:BB:CC:DD:EE:02", "rssi": -72},

    {"mac": "AA:BB:CC:DD:EE:03", "rssi": -80}

  ]

}

mcc=460(中国),mnc=0(移动),没插卡也填 460,0

bssids:≥3 个,否则定位失败

五、EDP 上报 WiFi 定位(你最关心的)

EDP 没有专门 WiFi 指令,用 0x03 普通数据点 上传到 $OneNET_LBS_WIFI。

✅ C# 完整方法(可直接用)

csharp

运行

// EDP 上报 WiFi 定位

public void UploadWiFi(string mac1, int rssi1,

                        string mac2, int rssi2,

                        string mac3, int rssi3)

{

    if (!_isLogin) return;


    // 组装WiFi定位JSON

    var json = $"{{\"mcc\":460,\"mnc\":0," +

               $"\"bssids\":[" +

               $"{{\"mac\":\"{mac1}\",\"rssi\":{rssi1}}}," +

               $"{{\"mac\":\"{mac2}\",\"rssi\":{rssi2}}}," +

               $"{{\"mac\":\"{mac3}\",\"rssi\":{rssi3}}}]}}";


    // EDP 0x03 上传到固定数据流

    UploadData("$OneNET_LBS_WIFI", json);

    Console.WriteLine("WiFi定位上报完成");

}

✅ 调用示例

csharp

运行

edp.UploadWiFi(

    "AA:BB:CC:DD:EE:01", -65,

    "AA:BB:CC:DD:EE:02", -72,

    "AA:BB:CC:DD:EE:03", -80

);


/// <summary> /// EDP 0x03 上传数据点(支持字符串、JSON、WiFi定位) /// </summary> /// <param name="streamName">数据流名(如 $OneNET_LBS_WIFI)</param> /// <param name="value">字符串值(WiFi定位JSON)</param> public void UploadData(string streamName, string value) {    if (!_isLogin || _stream == null) return;    try    {        using (MemoryStream ms = new MemoryStream())        using (BinaryWriter bw = new BinaryWriter(ms))        {            // ====================== EDP 0x03 标准包头 ======================            bw.Write((byte)0x03);       // 命令:上传数据点            bw.Write((byte)0x00);       // 保留位            // ====================== 数据流ID(名称) ======================            byte[] streamBuf = Encoding.UTF8.GetBytes(streamName);            bw.Write((ushort)streamBuf.Length);            bw.Write(streamBuf);            // ====================== 数据类型:字符串(0x03) ======================            bw.Write((byte)0x03); // 0x03 = 字符串类型            // ====================== 字符串长度 + 内容 ======================            byte[] valBuf = Encoding.UTF8.GetBytes(value);            bw.Write((uint)valBuf.Length); // 字符串长度(uint4字节)            bw.Write(valBuf);              // 字符串数据            // ====================== 发送数据包 ======================            byte[] packet = ms.ToArray();            _stream.Write(packet, 0, packet.Length);            _stream.Flush();            Console.WriteLine($"[EDP上传] {streamName} = {value}");        }    }    catch (Exception ex)    {        Console.WriteLine($"上传失败:{ex.Message}");    } }


六、MQTT/HTTP 上报(备用)

MQTT 主题

plaintext

$dp

Payload 同上 JSON,数据流 $OneNET_LBS_WIFI。

HTTP POST

plaintext

POST /devices/{device_id}/datapoints

Authorization: device-key {设备API-KEY}

Content-Type: application/json


{"datastreams":[{"id":"$OneNET_LBS_WIFI","datapoints":[{"value":"{上面JSON}"}]}]}

七、查询定位结果(平台 / API)

1. 控制台看位置

设备详情 → 位置信息 → 直接显示经纬度 + 地图。

2. API 查询(推荐)

plaintext

GET /devices/{device_id}/lbs

返回:

json

{

  "lon": 116.403874,

  "lat": 39.914885,

  "type": "wifi",

  "time": 1758067200

}

八、常见问题

上报成功但无位置:检查 bssids 是否 ≥3 个、mac 格式是否正确、是否开通 WiFi 定位。

精度差:多扫几个 WiFi(5–10 个),靠近窗口。

收费:每日免费 300 万次,一般用不完。

九、EDP vs MQTT(WiFi 定位)

EDP:二进制,包更小、省流量,适合 4G/NB-IoT

MQTT:文本,易调试,WiFi 模组常用


完整使用MQTT上传wifi信息,然后用HTTP获得位置信息的例子

MQTT 上传 WiFi 定位信息 → HTTP API 查询经纬度包含 Go 完整代码 + C# 完整代码,你直接复制就能用。

一、先记住 3 个固定规则(必须对)

MQTT 服务器:mqtt.heclouds.com:1883

WiFi 定位上报主题:$dp

WiFi 定位数据流:$OneNET_LBS_WIFI

上报格式:JSON 字符串(下面给)

二、Go 完整示例(MQTT 上传 + HTTP 查询)

1. 安装依赖

bash

运行

go get github.com/eclipse/paho.mqtt.golang

2. 完整代码(直接填参数就能跑)

go

运行

package main


import (

"encoding/json"

"fmt"

"io"

"net/http"

"time"


mqtt "github.com/eclipse/paho.mqtt.golang"

)


// ===================== 【改成你自己的信息】 =====================

const (

productID  = "你的产品ID"

deviceName = "你的设备名称"

deviceKey  = "设备APIKey"

masterKey  = "产品Master-APIKey" // 用于查询位置

deviceID   = "你的设备ID"         // 数字ID

)


func main() {

// ========== 1. 连接MQTT ==========

opts := mqtt.NewClientOptions()

opts.AddBroker("tcp://mqtt.heclouds.com:1883")

opts.SetClientID(productID + "&" + deviceName)

opts.SetUsername(productID)

opts.SetPassword(deviceKey)

opts.SetAutoReconnect(true)


client := mqtt.NewClient(opts)

if token := client.Connect(); token.Wait() && token.Error() != nil {

panic(token.Error())

}

fmt.Println("MQTT 连接成功")

time.Sleep(1 * time.Second)


// ========== 2. 组装WiFi定位数据 ==========

wifiData := map[string]interface{}{

"mcc": 460,

"mnc": 0,

"bssids": []map[string]interface{}{

{"mac": "11:22:33:44:55:66", "rssi": -60},

{"mac": "AA:BB:CC:DD:EE:FF", "rssi": -70},

{"mac": "00:11:22:33:44:55", "rssi": -75},

},

}

jsonData, _ := json.Marshal(wifiData)


// ========== 3. MQTT上报WiFi定位(固定主题 $dp) ==========

payload := fmt.Sprintf(`{"datastreams":[{"id":"$OneNET_LBS_WIFI","datapoints":[{"value":%s}]}]}`, string(jsonData))

token := client.Publish("$dp", 0, false, payload)

token.Wait()

fmt.Println("WiFi 定位上报成功")

fmt.Println("上报内容:", payload)


time.Sleep(2 * time.Second)


// ========== 4. HTTP API 查询位置 ==========

fmt.Println("\n====== 查询经纬度 ======")

getLocation()

}


// HTTP 查询设备当前位置

func getLocation() {

url := fmt.Sprintf("http://api.heclouds.com/devices/%s/lbs", deviceID)

req, _ := http.NewRequest("GET", url, nil)

req.Header.Set("api-key", masterKey)


client := &http.Client{}

resp, err := client.Do(req)

if err != nil {

panic(err)

}

defer resp.Body.Close()


body, _ := io.ReadAll(resp.Body)

fmt.Println("位置信息:")

fmt.Println(string(body))

}

三、C# 完整示例(MQTT 上传 + HTTP 查询)

1. NuGet

plaintext

Install-Package MQTTnet

Install-Package MQTTnet.Extensions.ManagedClient

2. 完整代码

csharp

运行

using System;

using System.Collections.Generic;

using System.Net.Http;

using System.Threading.Tasks;

using MQTTnet;

using MQTTnet.Client;


class OneNetWifiMqttDemo

{

    // ===================== 【改成你自己的】 =====================

    const string productId = "你的产品ID";

    const string deviceName = "你的设备名";

    const string deviceKey = "设备APIKey";

    const string masterKey = "产品MasterKey";

    const string deviceId = "设备数字ID";


    static async Task Main()

    {

        var factory = new MqttFactory();

        var client = factory.CreateMqttClient();


        // 1. 连接MQTT

        var options = new MqttClientOptionsBuilder()

            .WithTcpServer("mqtt.heclouds.com", 1883)

            .WithClientId($"{productId}&{deviceName}")

            .WithCredentials(productId, deviceKey)

            .Build();


        await client.ConnectAsync(options);

        Console.WriteLine("MQTT 连接成功");


        // 2. WiFi定位JSON

        var wifiObj = new

        {

            mcc = 460,

            mnc = 0,

            bssids = new[]

            {

                new { mac = "11:22:33:44:55:66", rssi = -60 },

                new { mac = "AA:BB:CC:DD:EE:FF", rssi = -70 },

                new { mac = "00:11:22:33:44:55", rssi = -78 }

            }

        };

        string wifiJson = System.Text.Json.JsonSerializer.Serialize(wifiObj);


        // 3. 上报固定格式

        string payload = $"{{\"datastreams\":[{{\"id\":\"$OneNET_LBS_WIFI\",\"datapoints\":[{{\"value\":{wifiJson}}}]}}]}}";


        // 4. 发布到主题 $dp

        var msg = new MqttApplicationMessageBuilder()

            .WithTopic("$dp")

            .WithPayload(payload)

            .Build();


        await client.PublishAsync(msg);

        Console.WriteLine("WiFi 定位上报完成");


        // 5. 查询位置

        await Task.Delay(2000);

        Console.WriteLine("\n====== 查询经纬度 ======");

        await GetLocation();

    }


    // HTTP 查询位置

    static async Task GetLocation()

    {

        using var http = new HttpClient();

        http.DefaultRequestHeaders.Add("api-key", masterKey);

        string url = $"http://api.heclouds.com/devices/{deviceId}/lbs";

        string res = await http.GetStringAsync(url);

        Console.WriteLine(res);

    }

}

四、运行后你会得到什么?

上报成功后,HTTP API 返回:

json

{

    "errno": 0,

    "data": {

        "lon": 116.403874,

        "lat": 39.914885,

        "radius": 30,

        "time": "2026-05-18 12:34:56",

        "type": "wifi"

    },

    "error": "succ"

}

type: wifi → 说明是 WiFi 定位

lon, lat → 经纬度

radius → 精度(米)

五、你必须填对的 5 个参数

productID

deviceName

deviceKey(设备 API 密钥)

masterKey(产品 Master 密钥)

deviceID(设备数字 ID)


当你同时上传 GPS + LBS 基站 + WIFI 三种定位数据时:

✅ OneNET 会优先返回精度最高的那个:

优先级顺序:

GPS(最高) > WIFI(第二) > LBS 基站(最低)

也就是说:

有 GPS 数据 → 永远返回 GPS 位置

没有 GPS / GPS 无效 → 返回 WIFI

GPS + WIFI 都没有 → 才返回 LBS 基站


你上传

GPS($OneNET_GPS)

WiFi($OneNET_LBS_WIFI)

LBS($OneNET_LBS)




上一篇:开源软件收集

Top