华为云应用侧Android Studio开发

本文将介绍如何使用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.xdnf.cn/news/1560462.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

CSS @规则(At-rules)系列详解___@charset规则使用方法

CSS 规则(At-rules)系列详解 ___charset规则使用方法 本篇目录&#xff1a; 零、时光宝盒 一、charset规则定义和用法 二、CSS charset语法 三、charset 使用方法例子 1、正确使用方法 2、无效的&#xff0c;错误的使用方法 零、时光宝盒 &#xff08;https://blog.csd…

C++ | Leetcode C++题解之第472题连接词

题目&#xff1a; 题解&#xff1a; struct Trie {bool isEnd;vector<Trie *> children;Trie() {this->children vector<Trie *>(26, nullptr);this->isEnd false;} };class Solution { public:Trie * trie new Trie();vector<string> findAllConc…

C语言 | Leetcode C语言题解之第472题连接词

题目&#xff1a; 题解&#xff1a; typedef struct Trie {struct Trie * children[26];bool isEnd; }Trie;#define TRIE_INITIAL(node) do { \for (int i 0; i < 26; i) { \(node)->children[i] NULL; \} \(node)->isEnd false; \ }while(0);static void freeTri…

第二阶段:mysql(学完就隐藏版)

第一章&#xff1a;部署数据库系统&#xff08;注意关闭防火墙&#xff0c;selinux安装&#xff09; 安装mysql配置的相关文件&#xff1a;yum install https://dev.mysql.com/get/mysql80-community-release-el7-5.noarch.rpm&#xff08;centos9&#xff1a;yum install http…

iOS--理解MVC与MVVM

MVC MVC 是一种将应用程序分为三部分的架构模式&#xff1a;Model&#xff08;模型&#xff09;、View&#xff08;视图&#xff09;、Controller&#xff08;控制器&#xff09;。每部分负责不同的职责&#xff0c;使代码更加模块化、易于维护。 • Model&#xff1a;负责业…

jmeter入门:脚本录制

1.设置代理。 网络连接-》代理-》手动设置代理. ip&#xff1a; 127.0.0.1&#xff0c; port&#xff1a;8888 2. add thread group 3. add HTTP(s) test script recorder, target controller chooses Test plan-> thread Group 4. click start. then open the browser …

Java | Leetcode Java题解之第472题连接词

题目&#xff1a; 题解&#xff1a; class Solution {Trie trie new Trie();public List<String> findAllConcatenatedWordsInADict(String[] words) {List<String> ans new ArrayList<String>();Arrays.sort(words, (a, b) -> a.length() - b.length(…

PyQt 的Tree Widget中拖放和点击的异常行为

在 PyQt 的 QTreeWidget 中&#xff0c;如果你遇到 拖放 和 点击 的异常行为&#xff0c;可能是由于信号处理、事件拦截、拖放设置或树结构配置等问题导致的。以下是一些可能的常见问题和解决方案。 1、问题背景 一个 PyQt 应用程序中包含两个 Tree Widget&#xff0c;当用户从…

QUUID 使用详解

UUID 通常由 128 位&#xff08;16 字节&#xff09;组成&#xff0c;通常表示为 32 个十六进制数字&#xff0c;分为五个部分&#xff0c;格式如下&#xff1a; QUuid 是 Qt 框架中用于生成和处理 UUID&#xff08;通用唯一标识符&#xff09;的类。UUID 是一种标准的标识符格…

(27)QPSK信号在非相关平坦莱斯(Rician)衰落信道上的误码率性能MATLAB仿真

文章目录 前言一、Rician衰落信道模型的MATLAB代码二、在非相关的平坦Rician衰落信道上传输QPSK符号模型1.MATLAB仿真代码2.仿真结果 前言 本文首先给出莱斯衰落信道的建模函数&#xff0c;然后基于该函数给出在非相关的平坦Rician衰落信道上传输QPSK数字调制符号的MATLAB仿真…

6. 继承、重写、super、final

文章目录 一、重新定义需求二、继承1. 继续分析2. 概念3. 代码① 父类② 子类③ 测试结果 4. 饿狼传说之多层继承① 概念② 代码 5. 多继承 三、方法的重写1. 情境2. 代码① 吃什么② 怎么叫(Override重写) 3. 小结 四、super1. 啃老2. 啃老啃到底 五、final1. 用途及特征2. 举…

快速解决urllib3.exceptions.MaxRetryError: HTTPSConnectionPool

正题 使用pip命令查看urllib3版本 pip list发现版本为 1.26.9 urllib3 v1.26.9此时如下报错&#xff0c;无法正常使用&#xff08;使用了代理&#xff09; urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(hostxxx.xxxxx.com, port443): Max retries exceeded wit…

智能的三大问题:何以、所以、可以

智能具有三大问题&#xff0c;即何以、所以、可以。“何以&#xff08;Why&#xff09;”涉及探讨智能的本质及其产生的原因。智能是什么&#xff1f;它的定义和特征是什么&#xff1f;为什么人类或机器需要智能&#xff1f;它如何帮助我们解决复杂问题、做出决策和适应环境&am…

(五)Proteus仿真STM32单片机串口数据流收发

&#xff08;五&#xff09;Protues仿真STM32单片机串口数据流收发 – ARMFUN 1&#xff0c;打开STM32CubeMX&#xff0c;找到USART1,配置模式Asynchronous&#xff0c;此时PA9、PA10自动变成串口模式 串口默认参数:115200bps 8bit None 1stop 2&#xff0c;NVIC Settings使能…

【Ubuntu】在Ubuntu上安装IDEA

【Ubuntu】在Ubuntu上安装IDEA 零、前言 最近换了Ubuntu系统&#xff0c;但是还得是要写代码&#xff0c;这样就不可避免地用到IDEA&#xff0c;接下来介绍一下如何在Ubuntu上安装IDEA。 壹、下载 这一步应该很容易的&#xff0c;直接打开IDEA的下载页面&#xff0c;点击下…

科研绘图系列:R语言绘制SCI文章图2

文章目录 介绍加载R包导入数据图a图b图d系统信息介绍 文章提供了绘制图a,图b和图d的数据和代码 加载R包 library(ggplot2) library(dplyr) library(readxl) library(ggpmisc)导入数据 数据可从以下链接下载(画图所需要的所有数据): 百度网盘下载链接: https://pan.baid…

2024年软件设计师中级(软考中级)详细笔记【3】数据结构(下)(分值5分)

上午题第3章数据结构下部目录 前言第3章 数据结构【下】(5分)3.5 查找3.5.1 查找的基本概念【考点】3.5.2 静态查找表的查找方法3.5.3 动态查找表3.5.4 哈希表3.5.4.1 哈希表的定义3.5.4.2 哈希函数的构造方法3.5.4.3 处理冲突的方法 3.6 排序3.6.1 排序的基本概念3.6.2 简单排…

Java 获取热搜并生成图片

效果图如下&#xff1a; 第一步获取热搜 public List<String> getHotNews4(Integer size) {if (size < 0 || StringUtils.isEmpty(size)) {return null;}try {//set 转listreturn new ArrayList<>(getHotNews(size));} catch (Exception e) {logger.error(&qu…

Java 集合 Collection常考面试题

理解集合体系图 collection中 list 是有序的,set 是无序的 什么是迭代器 主要遍历 Collection 集合中的元素,所有实现了 Collection 的集合类都有一个iterator()方法,可以返回一个 iterator 的迭代器。 ArrayList 和 Vector 的区别? ArrayList 可以存放 null,底层是由数…

Java控制台实现《多线程模拟龟兔赛跑》(实现Runnale接口,重写run()方法)

&#xff08;温馨提示&#xff1a;本题最重要的是学习思路&#xff0c;代码还有待优化和改进&#xff01;&#xff09; 下一篇博客进行优化。实现Callable接口&#xff1a;V call() throws Exception 。可以返回结果&#xff0c;以及可以抛出异常。&#xff08;启动线程比较麻烦…