华为云应用侧Android Studio开发

news2024/12/22 16:16:36

本文将介绍如何使用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";


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
       
        final Thread t = new Thread() {
            @Override
            public 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. 调用
@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tev = findViewById(R.id.tev);
        final Thread t = new Thread() {
            @Override
            public 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() {
                        @Override
                        public void onFailure(Call call, IOException e) {
                            // 处理网络错误或请求失败
                            runOnUiThread(() -> tev.setText("Error: " + e.getMessage()));
                        }

                        @Override
                        public void onResponse(Call call, Response response) throws IOException {
                            if (response.isSuccessful()) {
                                // 处理成功的响应并更新UI
                                String 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() {
        @Override
        public 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() {
                    @Override
                    public void onFailure(Call call, IOException e) {
                        // 处理网络错误或请求失败
                        runOnUiThread(() -> tev.setText("Error: " + e.getMessage()));
                    }

                    @Override
                    public void onResponse(Call call, Response response) throws IOException {
                        if (response.isSuccessful()) {
                            // 处理成功的响应并更新UI
                            String 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.coloradmin.cn/o/2204176.html

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

相关文章

开源全文搜索(搜索引擎)

吃水不忘挖井人&#xff0c;介绍Doug Cutting大牛是十分有必要的。 最早&#xff0c;接触到搜索引擎&#xff0c;知道有个Nutch&#xff08;开源搜索引擎&#xff09;&#xff0c;于是开始查看Nutch相关的资料&#xff0c;发现了Nutch的创始人Doug Cutting&#xff0c;随着项目…

Python 如何使用 Redis 作为缓存

Python 如何使用 Redis 作为缓存 一、引言 在现代 Web 应用程序和数据密集型服务中&#xff0c;性能 和 响应速度 是至关重要的因素。而当应用需要频繁访问相同的数据时&#xff0c;直接从数据库获取数据会耗费大量的时间和资源。因此&#xff0c;缓存系统成为了提升性能的重…

做一只由 OpenCV 控制的仿生手

这个项目介绍了如何制作和控制一只仿生手。作者最初受到Instagram上一个视频的启发&#xff0c;该视频展示了使用MPU6050传感器追踪手部动作并在屏幕上显示3D模型。作者决定将这个想法进一步发展&#xff0c;使用OpenCV来控制一只真实的仿生手。 大家好&#xff0c;在这篇教程中…

强大的PDF到Word转换工具

Solid Converter&#xff1a;强大的PDF到Word转换工具推荐 在日常工作和学习中&#xff0c;PDF是最常用的文件格式之一。然而&#xff0c;编辑PDF文档并不总是那么方便&#xff0c;尤其是当你需要将PDF文件转换为Word文档时。Solid Converter 是一款强大的工具&#xff0c;专为…

SpringBoot美发门店系统:数据驱动的决策

3系统分析 3.1可行性分析 通过对本美发门店管理系统实行的目的初步调查和分析&#xff0c;提出可行性方案并对其一一进行论证。我们在这里主要从技术可行性、经济可行性、操作可行性等方面进行分析。 3.1.1技术可行性 本美发门店管理系统采用SSM框架&#xff0c;JAVA作为开发语…

7.并发编程之并发安全问题

1 线程安全性 什么是线程安全性&#xff1f;可以这么理解&#xff0c; 我们所写的代码在并发情况下使用 时&#xff0c;总是能表现出正确的行为&#xff1b;反之&#xff0c;未实现线程安全的代码&#xff0c;表现的行为是不可预知的&#xff0c;有可能正确&#xff0c;而绝大多…

九寨沟,智慧旅游新名片

九寨沟属于自然类景区&#xff0c;以优美的自然风光取胜&#xff0c;景区文化内涵相对缺失。智慧化和文旅融合是智慧文旅景区的两个必备条件&#xff0c;九寨沟在智慧文旅景区建设过程中&#xff0c;经历了两个阶段&#xff0c;先是从传统景区迈向智慧景区&#xff0c;然后是充…

PostgreSQL学习笔记六:模式SCHEMA

模式&#xff08;Schema&#xff09; PostgreSQL中的模式&#xff08;Schema&#xff09;是一个命名的数据库对象集合&#xff0c;包括表、视图、索引、数据类型、函数、存储过程和操作符等。模式的主要作用是组织和命名空间数据库对象&#xff0c;使得同一个数据库中可以包含…

uniapp打包安卓apk步骤

然后安装在手机上就可以啦

MedMamba代码解释及用于糖尿病视网膜病变分类

MedMamba原理和用于糖尿病视网膜病变检测尝试 1.MedMamba原理 MedMamba发表于2024.9.28&#xff0c;是构建在Vision Mamba基础之上&#xff0c;融合了卷积神经网的架构&#xff0c;结构如下图&#xff1a; 原理简述就是图片输入后按通道输入后切分为两部分&#xff0c;一部分走…

每日论文18-24ISCAS采用磁调谐变压器低温CMOS28GHzVCO

《28 GHz VCO Using Magnetically Tuning Trifilar Transformer in Cryogenic CMOS Application 》24ISCAS 瞟到了这篇文章&#xff0c;开关真的是可以加在任何地方哈哈哈&#xff0c;还挺特别 通过改变电感偏压来改变Var的偏压&#xff0c;来拓宽带宽&#xff0c;其实是个挺简…

processing像素画教程

前提&#xff1a;各位已经安装了processing 第一步&#xff1a;创建一个简单的网格 我们首先创建一个网格来定义我们作品的像素画布。网格将帮助您在适当的位置绘制每个像素。 int gridSize 20; // 每个像素的大小 int cols, rows; void setup() {size(400, 400); // 设置画…

k8s 的网络通信

目录 1 k8s通信整体架构 2 flannel 网络插件 2.1 flannel 插件组成 2.2 flannel 插件的通信过程 2.3 flannel 支持的后端模式 3 calico 网络插件 3.1 calico 简介 3.2 calico 网络架构 3.3 部署 calico 1 k8s通信整体架构 k8s通过CNI接口接入其他插件来实现网络通讯。目前比较…

QTableView加入小灯泡

通过重载QAbstractTableModel中的data方法 QVariant CTblModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); int col index.column(); if (col ledColIndex && role Qt::DecorationRole) { return Q…

股指期货的杠杆是怎么体现和使用的?

股指期货的杠杆效应是通过保证金交易实现的。投资者只需支付合约价值的一小部分作为保证金&#xff0c;即可控制整个合约的价值。例如&#xff0c;如果一个股指期货合约的价值为100,000元&#xff0c;而保证金比例为10%&#xff0c;那么投资者只需支付10,000元即可控制这个合约…

PPT分享:埃森哲-业务流程BPM能力框架体系

PPT下载链接见文末~ 业务流程管理&#xff08;BPM, Business Process Management&#xff09;的能力框架体系是一个全面、系统的流程管理方法论和工具集&#xff0c;旨在帮助企业优化和持续改进其业务流程&#xff0c;从而提升运营效率和市场竞争力。 一、BPM能力框架体系概述…

云计算的江湖,风云再起

大数据产业创新服务媒体 ——聚焦数据 改变商业 还记得当年英特尔的广告语吗&#xff1f;“Intel Inside”&#xff0c;这个标志性的标签几乎成了计算设备的象征。然而&#xff0c;随着AI大模型的迅速崛起&#xff0c;计算的核心从CPU悄然转向了GPU。一场前所未有的技术革命正…

【学术会议征稿】第四届公共管理与大数据分析国际学术会议(PMBDA 2024)

第四届公共管理与大数据分析国际学术会议(PMBDA 2024) 2024 4th International Conference on Public Management and Big Data Analysis 第四届公共管理与大数据分析国际学术会议 &#xff08;PMBDA 2024&#xff09;将于2024年12月20-22日在中国青岛召开。会议主题主要围绕…

MySQL-表相关(DDL DML)

文章目录 表的基本操作表的创建表的删除 MySQL中的数据类型整数类型浮点数类型定点数类型日期和时间类型字符串类型charvarchartext 二进制类型 DDL语句查看建表语句修改表名新增字段修改字段(名类型)修改字段(仅类型)删除字段 表的基本操作 在介绍DDL和DQL的操作语句之前, 我…

HCIP-HarmonyOS Application Developer 习题(六)

&#xff08;多选&#xff09;1、Harmonyos多窗口交互能力提供了以下哪几种交互方式? A. 平行视界 B.全局消息通知 C.分屏 D.悬浮窗 答案&#xff1a;ACD 分析&#xff1a;系统提供了悬浮窗、分屏、平行视界三种多窗口交互&#xff0c;为用户在大屏幕设备上的多任务并行、便捷…