华为云应用侧Android Studio开发

ops/2025/2/11 8:32:12/

本文将介绍如何使用AndroidStudio开发APP完成与接入华为云IoTDA设备的对接,包括属性参数获以及取命令下发。

一、鉴权认证

应用侧需要通过IAM服务鉴权,获取token,华为账号创建 IAM 用户, 可以为创建的用户分配权限

华为云">认证鉴权_设备接入 IoTDA_华为云

1. 创建IAM账户

  1. 在统一身份认证服务,左侧导航窗格中,单击用户--->“创建用户”。
  2. 配置基本信息。创建用户界面填写用户信息访问方式。如需一次创建多个用户,可以单击添加用户”进行批量创建,每次最多可创建10个用户。
  3. 创建用户组
  4. 加入用户组并创建用户
  5. 为用户组授权

2. 获取IAM用户Token

IAM 用户需要通过 HTTPS 协议 POST 请求调用API 接口, 获取 IAM 用户的 Token,华为云认证通过后向应用服务器返回鉴权 X-SubjectToken。 该 Token 用于后续进一步的身份验证和授权操作。Token的有效期为24小时

2.1. 请求示例

POST: https://iam.myhuaweicloud.com/v3/auth/tokens

{"auth": {"identity": {"methods": ["password"],"password": {"user": {"domain": {"name": "IAMDomain"        //IAM用户所属账号名},"name": "IAMUser",             //IAM用户名"password": "IAMPassword"      //IAM用户密码}}},"scope": {"project": {"name": "xxxxxxxx"}}}
}

其中IAM用户名为IAMUser,IAM用户密码为IAMPassword,所属账号名为IAMDomain,在本次实验中个参数如下:

IAMUser:创建用户时填写的名字 DJ_IOT

IAMPassword:创建用户时填写的密码 ********

IAMDomain:在我的凭证界面,API凭证页签中,查看账号名、账号ID、用户名、用户ID、项目名称、项目ID。

3. 代码构造

3.1.  添加依赖

本次实验中使用OkHttp3库来发送HTTP请求,首先,在build.gradleapp/build.gradle)文件中添加OkHttp的依赖。

dependencies {implementation ("com.squareup.okhttp3:okhttp:4.9.3")
}

3.2. 声明权限

AndroidManifest.xml中声明网络权限,

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

3.3. 构建方法

该方法有4个入参分别是:租户名IAMDomain,用户名IAMUser,密码IAMPassword,请求地址iamTokenUrl,具体内容见上文。

private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
private static final OkHttpClient client = new OkHttpClient(); // 假设OkHttpClient是线程安全的,可以作为静态成员// 方法签名修改为接受必要的参数
public String getIAMToken(String huaweiName, String iamIname, String iamPassword, String iamTokenUrl) throws IOException {// 构建JSON请求体String jsonBody = String.format("{\"auth\": {\"identity\": {\"methods\": [\"password\"],\"password\": {\"user\": {\"domain\": {\"name\": \"%s\"},\"name\": \"%s\",\"password\": \"%s\"}}},\"scope\": {\"project\": {\"name\": \"cn-north-4\"}}}}",huaweiName, iamIname, iamPassword);RequestBody body = RequestBody.create(jsonBody, JSON);// 构建请求Request request = new Request.Builder().url(iamTokenUrl).post(body).addHeader("Content-Type", "application/json").build();// 发送请求并处理响应try (Response response = client.newCall(request).execute()) {if (!response.isSuccessful()) {// 输出错误内容System.out.println("Unexpected code " + response);throw new IOException("Unexpected code " + response);}// 从响应头中提取IAM令牌String iamToken = response.header("X-Subject-Token");if (iamToken == null || iamToken.isEmpty()) {// 记录警告日志(如果没有找到令牌)throw new IOException("IAM token not found");}return iamToken;} catch (IOException e) {// 记录异常日志throw e; // 重新抛出异常以便调用者可以处理}
}
3.4. 调用

在APP启动时调用一次,Android 禁止在主线程中进行网络操作,因为这可能会导致应用界面卡顿或冻结,所以调用的时候使用new Thread创建并启动线程。

String HUAWEINAME="xxxxxxx";  //华为账号名
String IAMINAME="xxxxxxx";    //IAM账户名
String IAMPASSWORD="xxxxxxx"; //IAM账户密码
String URL="https://iam.cn-north-4.myhuaweicloud.com/v3/auth/tokens?nocatalog=false";@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);final Thread t = new Thread() {@Overridepublic void run() {try {IoTDAUtils hw = new IoTDAUtils();String token = hw.getIAMToken(HUAWEINAME,IAMINAME,IAMPASSWORD,URL);System.out.println("获取token:" + token);} catch (Exception e) {e.printStackTrace();System.out.println("错误" + e.getMessage().toString());}}};t.start();}
3.5. token

在logcat中token已经打印出来

二、查看影子消息

        设备影子是一个用于存储和检索设备当前状态信息的JSON文档。每个设备有且只有一个设备影子,由设备ID唯一标识,设备影子用于存储设备上报的(状态)属性和应用程序期望的设备(状态)属性,无论该设备是否在线,都可以通过该影子获取和设置设备的属性。

        利用设备影子消息获取设备属性无论设备是否在线都可以查看最近一次上报的属性,如果使用查询设备属性功能需要与设备端联动下发查询指令设备端收到后上报指令,本次采用影子消息来获取设备属性。

华为云">查询设备影子数据_设备接入 IoTDA_华为云

1. URI

GET https://{endpoint}/v5/iot/{project_id}/devices/{device_id}/shadow

路径参数如下

参数

是否必选

参数类型

描述

project_id

String

参数说明:项目ID。获取方法请参见 获取项目ID

device_id

String

参数说明:设备ID,用于唯一标识一个设备。在注册设备时直接指定,

或者由物联网平台分配获得。 取值范围:长度不超过128,只允许字母、数字、下划线(_)、连接符(-)的组合。

请求参数如下:

参数

是否必选

参数类型

描述

X-Auth-Token

String

参数说明:用户Token。通过调用IAM服务 获取IAM用户Token接口获取,接口返回的响应消息头中X-Subject-Token就是需要获取的用户Token。简要的获取方法样例请参见 Token认证

Instance-Id

String

参数说明:实例ID。物理多租下各实例的唯一标识,建议携带该参数,在使用专业版时必须携带该参数。您可以在IoTDA管理控制台界面,选择左侧导航栏总览页签查看当前实例的ID,具体获取方式请参考查看实例详情

响应Body参数:

参数

参数类型

描述

device_id

String

设备ID,用于唯一标识一个设备。在注册设备时直接指定,或者由物联网平台分配获得。由物联网平台分配时,生成规则为"product_id" + "_" + "node_id"拼接而成。

shadow

Array of DeviceShadowData objects

设备影子数据结构体。

2. 代码构造

2.1. 构建方法
private static String IOTDA_ENDPOINT = "https://iotda.cn-north-4.myhuaweicloud.com/v5/iot/%s/devices/%s/shadow";
String project_id="*******************";
String device_id="********************";public void getDeviceShadow(String token,Callback callback) {IOTDA_ENDPOINT = String.format(IOTDA_ENDPOINT, project_id,device_id);Request request = new Request.Builder().url(IOTDA_ENDPOINT).addHeader("Content-Type", "application/json").addHeader("X-Auth-Token", token)  // 注意:这里应该使用有效的认证令牌.build();Call call = client.newCall(request);call.enqueue(callback);
}
2.2. 调用
@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);tev = findViewById(R.id.tev);final Thread t = new Thread() {@Overridepublic void run() {try {IoTDAUtils hw = new IoTDAUtils();AUTH_TOKEN = hw.getIAMToken(HUAWEINAME,IAMINAME,IAMPASSWORD,URL);System.out.println("获取token:" + AUTH_TOKEN);hw.getDeviceShadow(AUTH_TOKEN,new Callback() {@Overridepublic void onFailure(Call call, IOException e) {// 处理网络错误或请求失败runOnUiThread(() -> tev.setText("Error: " + e.getMessage()));}@Overridepublic void onResponse(Call call, Response response) throws IOException {if (response.isSuccessful()) {// 处理成功的响应并更新UIString responseBody = response.body().string();runOnUiThread(() -> tev.setText("Device Shadow: " + responseBody));} else {// 处理不成功的响应(如认证失败、资源未找到等)runOnUiThread(() -> tev.setText("Request failed: " + response.code()));}}});} catch (Exception e) {e.printStackTrace();System.out.println("错误" + e.getMessage().toString());}}};t.start();}
}

三、命令下发

华为云">下发设备命令_设备接入 IoTDA_华为云

1. URI

POST https://{endpoint}/v5/iot/{project_id}/devices/{device_id}/commands

路径参数

参数

是否必选

参数类型

描述

project_id

String

参数说明:项目ID。获取方法请参见 获取项目ID

device_id

String

参数说明:下发消息的设备ID,用于唯一标识一个设备,在注册设备时由物联网平台分配获得。 取值范围:长度不超过128,只允许字母、数字、下划线(_)、连接符(-)的组合。

请求Header参数

参数

是否必选

参数类型

描述

X-Auth-Token

String

参数说明:用户Token。通过调用IAM服务 获取IAM用户Token接口获取,接口返回的响应消息头中X-Subject-Token就是需要获取的用户Token。简要的获取方法样例请参见 Token认证

Instance-Id

String

参数说明:实例ID。物理多租下各实例的唯一标识,建议携带该参数,在使用专业版时必须携带该参数。您可以在IoTDA管理控制台界面,选择左侧导航栏总览页签查看当前实例的ID,具体获取方式请参考查看实例详情

请求Body参数

参数

是否必选

参数类型

描述

service_id

String

参数说明:设备命令所属的设备服务ID,在设备关联的产品模型中定义。 取值范围:长度不超过64的字符串。

最大长度:64

command_name

String

参数说明:设备命令名称,在设备关联的产品模型中定义。 取值范围:长度不超过128的字符串。

最大长度:128

paras

Object

参数说明:设备执行的命令,Json格式,里面是一个个键值对,如果serviceId不为空,每个键都是profile中命令的参数名(paraName);如果serviceId为空则由用户自定义命令格式。设备命令示例:{"value":"1"},具体格式需要应用和设备约定。此参数仅支持Json格式,暂不支持字符串。

最大长度:261952

请求示例

POST https://{endpoint}/v5/iot/{project_id}/devices/{device_id}/commands


{"service_id" : "reboot","command_name" : "ON_OFF","paras" : {"value" : "ON"}
}

2. 代码构造

2.1. 方法构造
private static String IOTDA_ENDPOINT_CMD = "https://iotda.cn-north-4.myhuaweicloud.com/v5/iot/%s/devices/%s/commands";public void sendDeviceCommand(String commandPayload,String token, Callback callback) {MediaType JSON = MediaType.parse("application/json; charset=utf-8");RequestBody body = RequestBody.create(JSON, commandPayload);IOTDA_ENDPOINT_CMD = String.format(IOTDA_ENDPOINT_CMD, project_id,device_id);Request request = new Request.Builder().url(IOTDA_ENDPOINT_CMD).post(body).addHeader("Content-Type", "application/json").addHeader("X-Auth-Token", token).build();client.newCall(request).enqueue(callback);
}
2.2. 调用
@Override
public void onClick(View view) {final Thread t = new Thread() {@Overridepublic void run() {try {IoTDAUtils hw = new IoTDAUtils();str_cmd = String.format(str_cmd, service_id,command_name,paras);System.out.println(str_cmd);hw.sendDeviceCommand(str_cmd,AUTH_TOKEN,new Callback() {@Overridepublic void onFailure(Call call, IOException e) {// 处理网络错误或请求失败runOnUiThread(() -> tev.setText("Error: " + e.getMessage()));}@Overridepublic void onResponse(Call call, Response response) throws IOException {if (response.isSuccessful()) {// 处理成功的响应并更新UIString responseBody = response.body().string();runOnUiThread(() -> tev.setText("Device Shadow: " + responseBody));} else {// 处理不成功的响应(如认证失败、资源未找到等)runOnUiThread(() -> tev.setText("Request failed: " + response.code()));}}});} catch (Exception e) {e.printStackTrace();System.out.println("错误" + e.getMessage().toString());}}};t.start();
}

四、工具类

根据以上内容整理完成IoTDAUtils工具类

package com.example.huawei_iotda_app;import java.io.IOException;import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;public class IoTDAUtils {private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");private static final OkHttpClient client = new OkHttpClient();public String getIAMToken(String huaweiName, String iamIname, String iamPassword, String iamTokenUrl) throws IOException {// 构建JSON请求体String jsonBody = String.format("{\"auth\": {\"identity\": {\"methods\": [\"password\"],\"password\": {\"user\": {\"domain\": {\"name\": \"%s\"},\"name\": \"%s\",\"password\": \"%s\"}}},\"scope\": {\"project\": {\"name\": \"cn-north-4\"}}}}",huaweiName, iamIname, iamPassword);RequestBody body = RequestBody.create(jsonBody, JSON);// 构建请求Request request = new Request.Builder().url(iamTokenUrl).post(body).addHeader("Content-Type", "application/json").build();// 发送请求并处理响应try (Response response = client.newCall(request).execute()) {if (!response.isSuccessful()) {// 输出错误内容System.out.println("Unexpected code " + response);throw new IOException("Unexpected code " + response);}// 从响应头中提取IAM令牌String iamToken = response.header("X-Subject-Token");if (iamToken == null || iamToken.isEmpty()) {// 记录警告日志(如果没有找到令牌)throw new IOException("IAM token not found");}return iamToken;} catch (IOException e) {// 记录异常日志throw e; // 重新抛出异常以便调用者可以处理}}public void getDeviceShadow(String token,String url,Callback callback) {Request request = new Request.Builder().url(url).addHeader("Content-Type", "application/json").addHeader("X-Auth-Token", token)  // 注意:这里应该使用有效的认证令牌.build();Call call = client.newCall(request);call.enqueue(callback);}public void sendDeviceCommand(String commandPayload,String token,String url, Callback callback) {MediaType JSON = MediaType.parse("application/json; charset=utf-8");RequestBody body = RequestBody.create(JSON, commandPayload);Request request = new Request.Builder().url(url).post(body).addHeader("Content-Type", "application/json").addHeader("X-Auth-Token", token).build();client.newCall(request).enqueue(callback);}
}

后续将按照以上内容开发一个便于测试的APP,可关注后续文章。

文章及源码地址:华为云应用侧Android测试APP-CSDN博客

 


http://www.ppmy.cn/ops/124115.html

相关文章

Nginx部署前端Vue项目的深度解析

目录 一、准备工作 1.1 开发环境 1.2 服务器环境 1.3 Nginx安装 二、构建Vue项目 三、上传静态文件到服务器 四、配置Nginx 五、测试并重新加载Nginx 六、访问Vue应用 七、高级配置 7.1 启用HTTPS 7.2 启用Gzip压缩 7.3 缓存控制 八、常见问题与解决方案 8.1 40…

ORA-01005: null password given; logon denied

Springboot项目更换数据库用户后启动服务报错提示&#xff1a;ORA-01005: null password given; logon denied 检查配置文件各项都正常&#xff0c;确认密码已经配置&#xff0c;确认数据库驱动与JDK相匹配后 可以尝试使用如下脚本设置数据库密码大小写不敏感 alter system …

28 基于51单片机的两路电压检测(ADC0808)

目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 基于51单片机&#xff0c;通过ADC0808获取两路电压&#xff0c;通过LCD1602显示 二、硬件资源 基于KEIL5编写C代码&#xff0c;PROTEUS8.15进行仿真&#xff0c;全部资源在页尾&#xff0c;提供…

OpenCV视频I/O(20)视频写入类VideoWriter之用于将图像帧写入视频文件函数write()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 cv::VideoWriter::write() 函数用于将图像帧写入视频文件。 该函数/方法将指定的图像写入视频文件。图像的大小必须与打开视频编写器时指定的大…

NebulaAI(企业数智化智能体)社区版正式上线!免费下载!

不知道在看这篇文章之前&#xff0c;您是否有体验过其他AI智能体平台。在操作使用过程中&#xff0c;脑海里有没有浮现过下面的问题? ○ 我想上传一些企业内部文档资料&#xff0c;开放的线上智能体环境存储安全吗&#xff1f;其他用户能看到我上传的文档内容吗&#xff1f; …

git 克隆时,SSL 连接失败解决方案

1. 检查网络连接 确保你能够访问 GitHub&#xff0c;尝试在浏览器中访问 https://github.com/microsoft/vcpkg.git&#xff0c;检查网络是否有问题。 2. 更新 Git 确保你使用的是最新版本的 Git&#xff0c;老版本的 Git 可能会有 SSL 相关的问题。你可以通过以下命令检查 G…

Vue2项目-自定义指令

一、自动获取焦点 1、main.js文件代码 Vue.directive("focus", {inserted(el) {el.querySelector("input").focus();}, }); 2、组件引用 <el-input v-focus></el-input>

Python和R及Julia妊娠相关疾病生物剖析算法

&#x1f3af;要点 算法使用了矢量投影、现代优化线性代数、空间分区技术和大数据编程利用相应向量空间中标量积和欧几里得距离的紧密关系来计算使用妊娠相关疾病&#xff08;先兆子痫&#xff09;、健康妊娠和癌症测试算法模型使用相关性投影利用相关性和欧几里得距离之间的关…