Fbuilke 发表于 2023-2-9 17:56:51

Arduino ESP32 WiFi定位

本帖最后由 Fbuilke 于 2023-2-9 18:02 编辑

​        最近项目用到定位,但是又不想重新画PCB,因此打算做一个仅通过WIFI来定位的小硬件,但找了很多家,比如高德、百度这些都没有面向个人开发者的硬件网络定位接口,兜兜转转还是找到了一家做物联网全域定位的公司叫维智科技,他们的物联网定位平台是这个https://lotboard.newayz.com/,个人开发者注册的话配额还是挺充裕的,特别是每日100次请求,很适合我们这些做智能硬件的。       根据开发手册体验了一下,只需要最少4个WiFi信息或者通过定位模块解析的坐标就可以返回详细的信息了,返回的数据是这样的。
{
    "id": "38efe26e-************************",
    "asset": "d1c09200-9254-11ed-*******************",
    "location": {
      "timestamp": 1673513233302,
      "address": {
            "name": "湖北省武汉市*************************************",
            "context": [
                {
                  "type": "Country",
                  "name": "中国",
                  "code": "CN"
                },
                {
                  "type": "Province",
                  "name": "湖北省",
                  "code": "420000"
                },
                {
                  "type": "City",
                  "name": "武汉市",
                  "code": "420100"
                },
                {
                  "type": "District",
                  "name": "****",
                  "code": "42****"
                },
                {
                  "type": "Township",
                  "name": "****",
                  "code": "42****"
                },
                {
                  "type": "Road",
                  "name": "****"
                },
                {
                  "type": "Building",
                  "name": "*********"
                },
                {
                  "type": "Floor",
                  "name": "*********"
                }
            ],
            "level": 14
      },
      "place": {
            "type": "Food",
            "name": "***********",
            "categories": [
                {
                  "id": 30200,
                  "name": "*****"
                }
            ],
            "distance": {
                "line": 15.863497
            }
      },
      "position": {
            "timestamp": 1673513234166,
            "source": "wifi",
            "point": {
                "longitude": 114.4*******,
                "latitude": 30.5******
            },
            "spatialReference": "gcj02",
            "accuracy": 29
      }
    }
}
data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==
可以看到还是挺详细的,配合第三方json库直接就可以解析得到当前地址和坐标了,对于无定位模块的设备来说简直是个福音,这样一下子能做的事情就变得多起来了,话不多说就拿这个平台做个定位硬件出来玩玩。
======================================================================================
这个平台的注册和设备注册我另外一个帖子已经写了,这里就不写了。https://blog.csdn.net/m0_50846041/article/details/128792973======================================================================================
我手上的话就是有一块ESP32-S2,如下图:
因为全程不需要其它引脚所以其它就不介绍了,直接开始。
整个流程就是:
可以看到还是非常简单的,首先引入头文件
#include <WiFi.h>data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==
接着在setup()中添加WiFi初始化和连接函数
void setup() {
Serial.begin(115200);
WiFi.mode(WIFI_STA);
WiFi.begin(id,psw);
while(WiFi.status()!=WL_CONNECTED){   
    delay(500);
    Serial.println("正在连接...");
}
Serial.println("连接成功!");   
delay(100);
Serial.println("Setup done");
}data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==
因为需要上传各个扫描到的WiFi 信息,所以我们定义一个结构体来装
typedef struct ap_info
{
unsigned char count;
String mac;
signed char rssi;
}apinfo;data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==
然后在最前面定义一个新函数用来控制WiFi扫描并赋值到刚刚创建的结构体上,也可以在最后面定义但是要声明。为了方便所以写前面,但代码多还是要写后面为妙。
data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==
void wifi_scan()
{
int n = WiFi.scanNetworks();
ApInfo.count =n;
Serial.println("scan done");
if (n == 0) {
    Serial.println("no networks found");
} else {
    Serial.print(n);
    Serial.println(" networks found");
    for (int i = 0; i < n; ++i) {
      ApInfo.rssi = WiFi.RSSI(i);
      ApInfo.mac = WiFi.BSSIDstr(i);
      delay(10);
    }
}
}接下来就是进行封装Json了,首先引入头文件和初始化封装和解析用到的部分,之所以设置这么大是因为有些地方WiFi较多如果设置很小会导致上传不全,接收也是一样的道理。
#include <ArduinoJson.h>

DynamicJsonDocument doc(8192);
DynamicJsonDocument rep(4096);data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==
如果报错的话需要去下载,期间可能会因为网络波动多次失败,实在不行就科学上网或者本地安装,这个教程很多就不叙述了。
定义一个Json封装函数用来构建post请求体,这个请求体的格式可以参考全域定位平台的API手册或者根据我下面这个格式去构建:
{
    "timestamp": 1670987434289,
    "id": "1675840238995-****************",
    "asset": {
      "id": "ea32ce50-9323-****************",
      "manufacturer": "esp32-s2"
    },
    "location": {
      "timestamp": 1670987434289,
      "wifis": [
            {
                "macAddress": "9E:2B:A6:89:40:D2",
                "signalStrength": -34
            },
            {
                "macAddress": "9E:2B:A6:99:40:D2",
                "signalStrength": -34
            },
            {
                "macAddress": "9E:2B:A6:A9:40:D2",
                "signalStrength": -34
            },
            {
                "macAddress": "40:67:9B:AD:12:5E",
                "signalStrength": -41
            }
      ]
    }
}data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==
arduino这个json库跟python一样操作简单,用惯了CJson库的这个简直是福音。
String JsonSerialization()
{
String message;
doc["timestamp"] = tmp_ll;
doc["id"] = "1675840238995-****************";
doc["asset"]["id"] = "ea32ce50-9323-****************";
doc["asset"]["manufacturer"] = "esp32-s2";
doc["location"]["timestamp"] = tmp_ll;
for(int i = 0;i < ApInfo.count;i++)
{
    doc["location"]["wifis"]["macAddress"] = WiFi.BSSIDstr(i);
    doc["location"]["wifis"]["signalStrength"] = WiFi.RSSI(i);
}
serializeJson(doc, message);// 序列化JSON数据并导出字符串
return message;
}data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==
完成上述后,就可以开始写请求部分了,首先需要引入头文件
#include <HTTPClient.h>data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==
ESP32的httpclient是这个
然后就是写请求,这部分还是很简单的,几行代码搞定
void get_location(String postMessage)
{
HTTPClient http;
http.begin("https://api.newayz.com/location/hub/v1/track_points?access_key=***********");      
http.addHeader("Content-Type", "application/json");
http.addHeader("Host", "api.newayz.com");
http.addHeader("Connection", "keep-alive");
int httpCode = http.POST(postMessage);
String payload = http.getString();                                    
Serial.println(httpCode);   
PraseJson(payload);
http.end();
}完成上述后,就是用相同的方式去解析请求回调的数据
void PraseJson(String json)
{
DeserializationError error = deserializeJson(rep, json);
if (error)
{
    Serial.print(F("prase failed: "));
    Serial.println(error.f_str());
    return;
}
const char * source = rep["location"]["position"]["source"];
const char * spatialReference = rep["location"]["position"]["spatialReference"];
double longitude = rep["location"]["position"]["point"]["longitude"];
double latitude = rep["location"]["position"]["point"]["latitude"];
const char * name = rep["location"]["address"]["name"];
Serial.print("当前地址:\t");
Serial.println(name);
Serial.print("当前经纬度坐标:\t");
Serial.print(longitude,6);
Serial.print("\t");
Serial.println(latitude,6);
Serial.print("定位获取来源:\t");
Serial.print(source);
Serial.print("\t坐标格式:\t");
Serial.println(spatialReference);
}data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==
最后一步就是在loop调用上述的函数去实现定位效果了
void loop() {
wifi_scan();
postMessage = JsonSerialization();
get_location(postMessage);
delay(5000);
// 重新连接
if (WiFi.status() != WL_CONNECTED) {
    Serial.println("Reconnecting to WiFi...");
    WiFi.disconnect();
    WiFi.reconnect();
}
}data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==
到这里就一切准备就绪了,全程不到100行代码轻松实现WiFi定位,解析定位效果如下
来到全域定位平台,他自带了监控大屏,上面可以看到当前设备所在位置
该平台还有电子围栏,轨迹查询等功能还需要各位自己去慢慢摸索,相应的API手册也很齐全,如果有什么问题欢迎留言,我会尽快回复。


​该贴原贴是在另外一个地方写的,不想重复工作所以移植一下https://blog.csdn.net/m0_50846041/article/details/128955571



页: [1]
查看完整版本: Arduino ESP32 WiFi定位