Browse Source

123123

tags/old_version_1
fyf 1 year ago
parent
commit
bab63fb5ad
18 changed files with 1395 additions and 7 deletions
  1. +1
    -0
      .idea/gradle.xml
  2. +8
    -3
      app/build.gradle
  3. BIN
     
  4. BIN
     
  5. BIN
     
  6. +8
    -2
      app/src/main/AndroidManifest.xml
  7. +2
    -0
      app/src/main/java/com/bonait/bnframework/business/MainInit.java
  8. +726
    -0
      app/src/main/java/com/bonait/bnframework/common/iot/AliyunIOTManager.java
  9. +24
    -0
      app/src/main/java/com/bonait/bnframework/common/iot/manager/IDemoCallback.java
  10. +330
    -0
      app/src/main/java/com/bonait/bnframework/common/iot/manager/InitManager.java
  11. +71
    -0
      app/src/main/java/com/bonait/bnframework/common/iot/manager/MD5Util.java
  12. +25
    -0
      app/src/main/java/com/bonait/bnframework/common/iot/manager/ToastUtils.java
  13. +56
    -0
      app/src/main/java/com/bonait/bnframework/common/iot/mode/AppLog.java
  14. +58
    -0
      app/src/main/java/com/bonait/bnframework/common/iot/mode/DeviceInfoData.java
  15. +4
    -0
      app/src/main/java/com/bonait/bnframework/modules/home/activity/BottomNavigation2Activity.java
  16. +6
    -0
      app/src/main/java/com/bonait/bnframework/modules/home/fragment/Home1Fragment.java
  17. +70
    -0
      app/src/main/res/raw/deviceinfo
  18. +6
    -2
      build.gradle

+ 1
- 0
.idea/gradle.xml View File

@@ -7,6 +7,7 @@
<option name="testRunner" value="GRADLE" /> <option name="testRunner" value="GRADLE" />
<option name="distributionType" value="DEFAULT_WRAPPED" /> <option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" /> <option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="JDK" />
<option name="modules"> <option name="modules">
<set> <set>
<option value="$PROJECT_DIR$" /> <option value="$PROJECT_DIR$" />


+ 8
- 3
app/build.gradle View File

@@ -1,6 +1,7 @@
apply plugin: 'com.android.application' apply plugin: 'com.android.application'
//apply plugin: 'com.jakewharton.butterknife' //apply plugin: 'com.jakewharton.butterknife'



android { android {
compileSdk rootProject.ext.compileSdkVersion compileSdk rootProject.ext.compileSdkVersion


@@ -117,9 +118,7 @@ dependencies {
// debugImplementation 'com.squareup.leakcanary:leakcanary-support-fragment:1.6.3' // debugImplementation 'com.squareup.leakcanary:leakcanary-support-fragment:1.6.3'
// implementation files('libs/commons-codec-1.6.jar') // implementation files('libs/commons-codec-1.6.jar')


//MQTT
implementation files('libs\\org.eclipse.paho.android.service-1.1.1.jar')
implementation files('libs\\org.eclipse.paho.client.mqttv3-1.2.5.jar')



//Modbus //Modbus
implementation 'com.github.licheedev:Modbus4Android:2.0.2' implementation 'com.github.licheedev:Modbus4Android:2.0.2'
@@ -147,4 +146,10 @@ dependencies {


//轻量级sw //轻量级sw
implementation 'com.github.zcweng:switch-button:0.0.3@aar' implementation 'com.github.zcweng:switch-button:0.0.3@aar'

//阿里云IOT
implementation ('com.aliyun.alink.linksdk:lp-iot-linkkit:1.7.3.2')
//MQTT
// implementation files('libs\\org.eclipse.paho.android.service-1.1.1.jar')
// implementation files('libs\\org.eclipse.paho.client.mqttv3-1.2.5.jar')
} }

BIN
View File


BIN
View File


BIN
View File


+ 8
- 2
app/src/main/AndroidManifest.xml View File

@@ -15,6 +15,9 @@
<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />


<uses-sdk tools:overrideLibrary="com.aliyun.iot.breeze.biz,com.aliyun.iot.breeze.ota,
com.aliyun.iot.breeze.sdk,com.aliyun.iot.ble,com.aliyun.alink.linksdk.tmp"/>

<application <application
android:name=".MainApplication" android:name=".MainApplication"
android:allowBackup="true" android:allowBackup="true"
@@ -27,7 +30,8 @@
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/AppTheme" android:theme="@style/AppTheme"
tools:ignore="GoogleAppIndexingWarning" tools:ignore="GoogleAppIndexingWarning"
tools:node="merge">
tools:node="merge"
tools:replace="android:icon">
<activity <activity
android:name=".modules.home.fragment.from.fragment.SystemCsPLCFragment" android:name=".modules.home.fragment.from.fragment.SystemCsPLCFragment"
android:exported="false" tools:ignore="Instantiatable"/> android:exported="false" tools:ignore="Instantiatable"/>
@@ -128,7 +132,7 @@
<activity android:name=".modules.home.activity.BottomNavigation2Activity" /> <activity android:name=".modules.home.activity.BottomNavigation2Activity" />
<activity android:name=".modules.home.activity.BottomNavigationActivity" /> <activity android:name=".modules.home.activity.BottomNavigationActivity" />


<service android:name="org.eclipse.paho.android.service.MqttService" />
<!-- <service android:name="org.eclipse.paho.android.service.MqttService" />-->


<receiver <receiver
android:name=".common.base.BootReceiver" android:name=".common.base.BootReceiver"
@@ -139,6 +143,8 @@
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</receiver> </receiver>


</application> </application>


</manifest> </manifest>

+ 2
- 0
app/src/main/java/com/bonait/bnframework/business/MainInit.java View File

@@ -93,6 +93,8 @@ public class MainInit {
InitDBdata(); InitDBdata();
DataBus.getInstance().GetLc();//获取料仓数据 DataBus.getInstance().GetLc();//获取料仓数据
ConfigData.getInstance().LoadingCloud();//加载云端数据 ConfigData.getInstance().LoadingCloud();//加载云端数据


} }


//========================================================================// //========================================================================//


+ 726
- 0
app/src/main/java/com/bonait/bnframework/common/iot/AliyunIOTManager.java View File

@@ -0,0 +1,726 @@
package com.bonait.bnframework.common.iot;

import android.content.Context;
import android.text.TextUtils;
import android.util.Log;

import com.alibaba.fastjson.JSONObject;
import com.aliyun.alink.dm.api.BaseInfo;
import com.aliyun.alink.dm.api.DeviceInfo;
import com.aliyun.alink.dm.api.IThing;
import com.aliyun.alink.linkkit.api.LinkKit;
import com.aliyun.alink.linksdk.tmp.api.InputParams;
import com.aliyun.alink.linksdk.tmp.api.OutputParams;
import com.aliyun.alink.linksdk.tmp.device.payload.ValueWrapper;
import com.aliyun.alink.linksdk.tmp.devicemodel.Arg;
import com.aliyun.alink.linksdk.tmp.devicemodel.Event;
import com.aliyun.alink.linksdk.tmp.devicemodel.Property;
import com.aliyun.alink.linksdk.tmp.devicemodel.Service;
import com.aliyun.alink.linksdk.tmp.listener.IPublishResourceListener;
import com.aliyun.alink.linksdk.tmp.listener.ITResRequestHandler;
import com.aliyun.alink.linksdk.tmp.listener.ITResResponseCallback;
import com.aliyun.alink.linksdk.tmp.utils.ErrorInfo;
import com.aliyun.alink.linksdk.tmp.utils.GsonUtils;
import com.aliyun.alink.linksdk.tmp.utils.TmpConstant;
import com.aliyun.alink.linksdk.tools.AError;
import com.bonait.bnframework.MainApplication;
import com.bonait.bnframework.R;
import com.bonait.bnframework.common.iot.manager.IDemoCallback;
import com.bonait.bnframework.common.iot.manager.InitManager;
import com.bonait.bnframework.common.iot.mode.AppLog;
import com.bonait.bnframework.common.iot.mode.DeviceInfoData;
import com.bonait.bnframework.common.utils.ToastUtils;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

public class AliyunIOTManager {

//region 变量
private static final String TAG = "阿里云";
/**
* 判断是否初始化完成
* 未初始化完成,所有和云端的长链通信都不通
*/
public static boolean isInitDone = false;
public static boolean userDevInfoError = false;
public static DeviceInfoData mDeviceInfoData = null;
public static String productKey = null, deviceName = null, deviceSecret = null, productSecret = null,
password = null, username = null, clientId = null, deviceToken = null, mqttHost = null, instanceId = null;
private String registerType = null;
private final static int DEF_VALUE = Integer.MIN_VALUE;
final static Pattern pattern = Pattern.compile("^[-\\+]?[.\\d]*$");
private Map<String, ValueWrapper> reportData = null;
private boolean isSubDev = false;
private final static String SERVICE_SET = "set";
private final static String SERVICE_GET = "get";
//endregion

//region 单例
private static AliyunIOTManager instance;

private AliyunIOTManager() {
reportData =new HashMap<String, ValueWrapper>();
// 从 raw 读取指定配置文件
String testData = getFromRaw();
// 解析数据
getDeviceInfoFrom(testData);
}

public static synchronized AliyunIOTManager getInstance() {
if (instance == null) {
instance = new AliyunIOTManager();
}
return instance;
}
//endregion

//region 公有

/**
* 打开设备
*/
public void OpenDev(Context context) {
try {
if (userDevInfoError) {
ToastUtils.warning("三元组文件格式不正确,请重新检查格式");
} else {
if (!TextUtils.isEmpty(deviceSecret) || !TextUtils.isEmpty(password) || !TextUtils.isEmpty(deviceToken)) {
connect(context);
} else {
if (!userDevInfoError) {
ToastUtils.warning("三元组信息无效,请重新填写");
}
userDevInfoError = true;
}
}
} catch (Exception ex) {

}
}

/**
* 耗时操作,建议放到异步线程
* 反初始化同步接口
*/
public void CloseDev() {
AppLog.d(TAG, "deinit");
isInitDone = false;
new Thread(new Runnable() {
@Override
public void run() {
// 同步接口
LinkKit.getInstance().deinit();
ToastUtils.info("关闭IOT成功");
}
}).start();
}

/**
* 获取设备属性
*
* @return
*/
public List<Property> GetProperty() {
return LinkKit.getInstance().getDeviceThing().getProperties();
}

/**
* 上报属性
* @param property
*/
public void UploadProperty(Property property, String val) {
try {
if (property == null) {
showToast("选择的property为空");
return;
}
String value = val;
if (property == null || value == null || property.getIdentifier() == null) {
showToast("属性或值为空");
return;
}
if (property.getDataType() == null) {
showToast("属性类型为空");
return;
}
if (TmpConstant.TYPE_VALUE_INTEGER.equals(property.getDataType().getType())) {
int parseData = getInt(value);
if (parseData != DEF_VALUE) {
report(property.getIdentifier(), new ValueWrapper.IntValueWrapper(parseData));
} else {
showToast("数据格式不对");
}
return;
}
if (TmpConstant.TYPE_VALUE_FLOAT.equals(property.getDataType().getType())) {
Double parseData = getDouble(value);
if (parseData != null) {
report(property.getIdentifier(), new ValueWrapper.DoubleValueWrapper(parseData));
} else {
showToast("数据格式不对");
}
return;
}
if (TmpConstant.TYPE_VALUE_DOUBLE.equals(property.getDataType().getType())) {
Double parseData = getDouble(value);
if (parseData != null) {
report(property.getIdentifier(), new ValueWrapper.DoubleValueWrapper(parseData));
} else {
showToast("数据格式不对");
}
return;
}
if (TmpConstant.TYPE_VALUE_BOOLEAN.equals(property.getDataType().getType())) {
int parseData = getInt(value);
if (parseData == 0 || parseData == 1) {
report(property.getIdentifier(), new ValueWrapper.BooleanValueWrapper(parseData));
} else {
showToast("数据格式不对");
}
return;
}
if (TmpConstant.TYPE_VALUE_TEXT.equals(property.getDataType().getType())) {
report(property.getIdentifier(), new ValueWrapper.StringValueWrapper(value));
return;
}
if (TmpConstant.TYPE_VALUE_DATE.equals(property.getDataType().getType())) {
report(property.getIdentifier(), new ValueWrapper.DateValueWrapper(value));
return;
}
if (TmpConstant.TYPE_VALUE_ENUM.equalsIgnoreCase(property.getDataType().getType())) {
report(property.getIdentifier(), new ValueWrapper.EnumValueWrapper(getInt(value)));
return;
}
if (TmpConstant.TYPE_VALUE_ARRAY.equalsIgnoreCase(property.getDataType().getType())) {
ValueWrapper.ArrayValueWrapper arrayValueWrapper = GsonUtils.fromJson(value, new TypeToken<ValueWrapper>() {
}.getType());
report(property.getIdentifier(), arrayValueWrapper);
return;
}
// 结构体数据解析 结构体不支持嵌套结构体和数组
if (TmpConstant.TYPE_VALUE_STRUCT.equals(property.getDataType().getType())) {
try {
List<Map<String, Object>> specsList = (List<Map<String, Object>>) property.getDataType().getSpecs();
if (specsList == null || specsList.size() == 0) {
showToast("云端创建的struct结构为空,不上传任何值。");
return;
}
JSONObject dataJson = JSONObject.parseObject(value);
Map<String, ValueWrapper> dataMap = new HashMap<>();
Map<String, Object> specsItem = null;
for (int i = 0; i < specsList.size(); i++) {
specsItem = specsList.get(i);
if (specsItem == null) {
continue;
}
String idKey = (String) specsItem.get("identifier");
String dataType = (String) ((Map) specsItem.get("dataType")).get("type");
if (idKey != null && dataJson.containsKey(idKey) && dataType != null) {
ValueWrapper valueItem = null;
if ("int".equals(dataType)) {
valueItem = new ValueWrapper.IntValueWrapper(getInt(String.valueOf(dataJson.get(idKey))));
} else if ("text".equals(dataType)) {
valueItem = new ValueWrapper.StringValueWrapper((String) dataJson.get(idKey));
} else if ("float".equals(dataType) || "double".equals(dataType)) {
valueItem = new ValueWrapper.DoubleValueWrapper(getDouble(String.valueOf(dataJson.get(idKey))));
} else if ("bool".equals(dataType)) {
valueItem = new ValueWrapper.BooleanValueWrapper(getInt(String.valueOf(dataJson.get(idKey))));
} else if ("date".equals(dataType)) {
if (isValidInt(String.valueOf(dataJson.get(idKey)))) {
valueItem = new ValueWrapper.DateValueWrapper(String.valueOf(dataJson.get(idKey)));
} else {
showToast("数据格式不对");
}
} else if ("enum".equals(dataType)) {
valueItem = new ValueWrapper.EnumValueWrapper(getInt(String.valueOf(dataJson.get(idKey))));
} else {
showToast("数据格式不支持");
}
if (valueItem != null) {
dataMap.put(idKey, valueItem);
}
}
}

report(property.getIdentifier(), new ValueWrapper.StructValueWrapper(dataMap));
} catch (Exception e) {
showToast("数据格式不正确");
}
return;
}
showToast("该类型Demo暂不支持,用户可参照其他类型代码示例开发支持。");
} catch (Exception e) {
showToast("数据格式不对");
e.printStackTrace();
}
}

/**
* 获取设备服务,
*
* @return
*/
public List<Service> GetService() {
return LinkKit.getInstance().getDeviceThing().getServices();
}

/**
* 监听服务
*/
public void MonitorService()
{
List<Service> services= LinkKit.getInstance().getDeviceThing().getServices();
for (Service item:services)
{
LinkKit.getInstance().getDeviceThing().thingServiceRegister(item.getName(),itResRequestHandler);
}
}

/**
* 获取设备事件
*
* @return
*/
public List<Event> GetEvents() {
return LinkKit.getInstance().getDeviceThing().getEvents();
}

/**
* 上报事件通知
* @param event
* @param val
*/
public void UploadEvents(Event event, String val) {
if (event == null) {
showToast("事件不能为空");
return;
}

HashMap<String, ValueWrapper> hashMap = new HashMap<>();
try {
String mapEventData = val;
JSONObject object = JSONObject.parseObject(mapEventData);
if (object == null){
showToast("参数不能为空");
return;
}
if (event.getOutputData() != null) {
for (int i = 0; i < event.getOutputData().size(); i++) {
Arg arg = event.getOutputData().get(i);
if (arg == null || arg.getDataType() == null || arg.getIdentifier() == null){
continue;
}
String idnValue = String.valueOf(object.get(arg.getIdentifier()));
if (idnValue == null || object.get(arg.getIdentifier()) == null){
continue;
}
if (TmpConstant.TYPE_VALUE_INTEGER.equals(arg.getDataType().getType())) {
int parseData = getInt(idnValue);
if (parseData != DEF_VALUE) {
hashMap.put(arg.getIdentifier(), new ValueWrapper.IntValueWrapper(parseData));
} else {
showToast("数据格式不对");
break;
}
continue;
}
if (TmpConstant.TYPE_VALUE_FLOAT.equals(arg.getDataType().getType())) {
Double parseData = getDouble(idnValue);
if (parseData != null) {
hashMap.put(arg.getIdentifier(), new ValueWrapper.DoubleValueWrapper(parseData));
} else {
showToast("数据格式不对");
break;
}
continue;
}
if (TmpConstant.TYPE_VALUE_DOUBLE.equals(arg.getDataType().getType())) {
Double parseData = getDouble(idnValue);
if (parseData != null) {
hashMap.put(arg.getIdentifier(), new ValueWrapper.DoubleValueWrapper(parseData));
} else {
showToast("数据格式不对");
break;
}
continue;
}
if (TmpConstant.TYPE_VALUE_BOOLEAN.equals(arg.getDataType().getType())) {
int parseData = getInt(idnValue);
if (parseData == 0 || parseData == 1) {
hashMap.put(arg.getIdentifier(), new ValueWrapper.BooleanValueWrapper(parseData));
} else {
showToast("数据格式不对");
break;
}
continue;
}
if (TmpConstant.TYPE_VALUE_TEXT.equals(arg.getDataType().getType())) {
hashMap.put(arg.getIdentifier(), new ValueWrapper.StringValueWrapper(idnValue));
continue;
}
if (TmpConstant.TYPE_VALUE_DATE.equals(arg.getDataType().getType())) {
hashMap.put(arg.getIdentifier(), new ValueWrapper.DateValueWrapper(idnValue));
continue;
}
if(TmpConstant.TYPE_VALUE_ENUM.equalsIgnoreCase(arg.getDataType().getType())){
hashMap.put(arg.getIdentifier(),new ValueWrapper.EnumValueWrapper(getInt(idnValue)));
continue;
}
if(TmpConstant.TYPE_VALUE_ARRAY.equalsIgnoreCase(arg.getDataType().getType())){
ValueWrapper.ArrayValueWrapper arrayValueWrapper = GsonUtils.fromJson(idnValue,new TypeToken<ValueWrapper>(){}.getType());
hashMap.put(arg.getIdentifier(),arrayValueWrapper);
continue;
}
}
}
} catch (Exception e) {
e.printStackTrace();
showToast("数据格式错误");
return;
}
try {
OutputParams params = new OutputParams(hashMap);
if (!isSubDev) {
LinkKit.getInstance().getDeviceThing().thingEventPost(event.getIdentifier(), params, resourceListener);
} else {
// IThing thing = LinkKit.getInstance().getGateway().getSubDeviceThing(mBaseInfo).first;
// if (thing == null){
// showToast("子设备当前状态不支持");
// return;
// }
// thing.thingEventPost(event.getIdentifier(), params, resourceListener);
}
} catch (Exception e) {
e.printStackTrace();
showToast("上报失败 " + e);
}
}
//endregion

//region 私有

/**
* 初始化建联
* 如果初始化建联失败,需要用户重试去完成初始化,并确保初始化成功。如应用启动的时候无网络,导致失败,可以在网络可以的时候再次执行初始化,成功之后不需要再次执行。
* 初始化成功之后,如果因为网络原因连接断开了,用户不需要执行初始化建联操作,SDK会处理建联。
* <p>
* onError 初始化失败
* onInitDone 初始化成功
* <p>
* SDK 支持以userName+password+clientId 的方式登录(不推荐,建议使用三元组建联)
* 设置如下参数,InitManager.init的时候 deviceSecret, productSecret 可以不填
* MqttConfigure.mqttUserName = username;
* MqttConfigure.mqttPassWord = password;
* MqttConfigure.mqttClientId = clientId;
*/
private void connect(Context context) {
AppLog.d(TAG, "connect() called");
InitManager.init(context, productKey, deviceName, deviceSecret, productSecret, mqttHost, new IDemoCallback() {
@Override
public void onError(AError aError) {
AppLog.d(TAG, "onError() called with: aError = [" + InitManager.getAErrorString(aError) + "]");
// 初始化失败,初始化失败之后需要用户负责重新初始化
// 如一开始网络不通导致初始化失败,后续网络恢复之后需要重新初始化
if (aError != null) {
AppLog.d(TAG, "初始化IOT失败,错误信息:" + aError.getCode() + "-" + aError.getSubCode() + ", " + aError.getMsg());
// ToastUtils.error("初始化IOT失败,错误信息:" + aError.getCode() + "-" + aError.getSubCode() + ", " + aError.getMsg());
} else {
AppLog.d(TAG, "初始化IOT失败");
//ToastUtils.error("初始化IOT失败");
}
}

@Override
public void onInitDone(Object data) {
AppLog.d(TAG, "初始化IOT成功: data = [" + data + "]");
isInitDone = true;


}
});
}

/**
* 注意:该场景只适合于设备未激活的场景
* 验证一型一密 需要以下步骤:
* 1.云端创建产品,开启产品的动态注册功能;
* 2.创建一个设备,在文件中(raw/deviceinfo)填写改设备信息 productKey,deviceName, productSecret;
* 3.通过这三个信息可以去云端动态拿到deviceSecret,并建立长连接;
*
* @return
*/
public String getFromRaw() {
InputStreamReader inputReader = null;
BufferedReader bufReader = null;
try {
inputReader = new InputStreamReader(MainApplication.getContext().getResources().openRawResource(R.raw.deviceinfo));
bufReader = new BufferedReader(inputReader);
String line = "";
String Result = "";
while ((line = bufReader.readLine()) != null)
Result += line;
return Result;
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (bufReader != null) {
bufReader.close();
}
if (inputReader != null) {
inputReader.close();
}
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}

/**
* 解析数据
*
* @param testData
*/
private void getDeviceInfoFrom(String testData) {
AppLog.d(TAG, "getDeviceInfoFrom() called with: testData = [" + testData + "]");
try {
if (testData == null) {
AppLog.e(TAG, "getDeviceInfoFrom: data empty.");
userDevInfoError = true;
return;
}
Gson mGson = new Gson();
DeviceInfoData deviceInfoData = mGson.fromJson(testData, DeviceInfoData.class);
if (deviceInfoData == null) {
AppLog.e(TAG, "getDeviceInfoFrom: file format error.");
userDevInfoError = true;
return;
}
AppLog.d(TAG, "getDeviceInfoFrom deviceInfoData=" + deviceInfoData);
if (checkValid(deviceInfoData)) {
mDeviceInfoData = new DeviceInfoData();
mDeviceInfoData.productKey = deviceInfoData.productKey;
mDeviceInfoData.productSecret = deviceInfoData.productSecret;
mDeviceInfoData.deviceName = deviceInfoData.deviceName;
mDeviceInfoData.deviceSecret = deviceInfoData.deviceSecret;
mDeviceInfoData.username = deviceInfoData.username;
mDeviceInfoData.password = deviceInfoData.password;
mDeviceInfoData.clientId = deviceInfoData.clientId;
mDeviceInfoData.deviceToken = deviceInfoData.deviceToken;
mDeviceInfoData.registerType = deviceInfoData.registerType;
mDeviceInfoData.mqttHost = deviceInfoData.mqttHost;
mDeviceInfoData.instanceId = deviceInfoData.instanceId;

userDevInfoError = false;

mDeviceInfoData.subDevice = new ArrayList<>();
if (deviceInfoData.subDevice == null) {
AppLog.d(TAG, "getDeviceInfoFrom: subDevice empty..");
return;
}
for (int i = 0; i < deviceInfoData.subDevice.size(); i++) {
if (checkValid(deviceInfoData.subDevice.get(i))) {
mDeviceInfoData.subDevice.add(deviceInfoData.subDevice.get(i));
} else {
AppLog.d(TAG, "getDeviceInfoFrom: subDevice info invalid. discard.");
}
}

productKey = mDeviceInfoData.productKey;
deviceName = mDeviceInfoData.deviceName;
deviceSecret = mDeviceInfoData.deviceSecret;
productSecret = mDeviceInfoData.productSecret;
password = mDeviceInfoData.password;
username = mDeviceInfoData.username;
clientId = mDeviceInfoData.clientId;
deviceToken = mDeviceInfoData.deviceToken;
registerType = mDeviceInfoData.registerType;
mqttHost = mDeviceInfoData.mqttHost;
instanceId = mDeviceInfoData.instanceId;

AppLog.d(TAG, "getDeviceInfoFrom: final data=" + mDeviceInfoData);
} else {
AppLog.e(TAG, "res/raw/deviceinfo error.");
userDevInfoError = true;
}

} catch (Exception e) {
AppLog.e(TAG, "getDeviceInfoFrom: e", e);
userDevInfoError = true;
}

}

private boolean checkValid(BaseInfo baseInfo) {
if (baseInfo == null) {
return false;
}
if (TextUtils.isEmpty(baseInfo.productKey) || TextUtils.isEmpty(baseInfo.deviceName)) {
return false;
}
if (baseInfo instanceof DeviceInfoData) {
if (TextUtils.isEmpty(((DeviceInfo) baseInfo).productSecret) && TextUtils.isEmpty(((DeviceInfo) baseInfo).deviceSecret) && TextUtils.isEmpty(((DeviceInfoData) baseInfo).password)) {
return false;
}
}
return true;
}

private static void showToast(String message)
{
ToastUtils.info(message);
}

private boolean isValidDouble(String value) {
if (TextUtils.isEmpty(value)) {
return false;
}
try {
if (pattern != null && pattern.matcher(value) != null) {
if (pattern.matcher(value).matches()) {
return true;
}
}
} catch (Exception e) {
e.printStackTrace();
}
return false;
}

private Double getDouble(String value) {
if (isValidDouble(value)) {
return Double.parseDouble(value);
}
return null;
}

private boolean isValidInt(String value) {
return !TextUtils.isEmpty(value);
}

private int getInt(String value) {
if (isValidInt(value)) {
try {
return Integer.parseInt(value);
} catch (Exception e) {
e.printStackTrace();
}
}
return DEF_VALUE;
}

private void report(String identifier, ValueWrapper valueWrapper) {
reportData.clear();
Map<String, ValueWrapper> reportData = new HashMap<>();
/**
* 物模型默认的模块中,属性的identifer是不用加前缀的. 比如名为lightSwitch的属性, identifer就是lightSwitch
* 如果是用户自定义的模块,属性的identifer前要加"模块名:"这样的前缀. 比如myBlock模块中的lightSwitch属性,
* identifer就要写成"myBlock:lightSwitch"
*/
reportData.put(identifier, valueWrapper);
if (!isSubDev) {
try {
LinkKit.getInstance().getDeviceThing().thingPropertyPost(reportData, resourceListener);
} catch (Exception e) {
e.printStackTrace();
showToast("上报失败 " + e);
}
} else {
try {
// IThing thing = LinkKit.getInstance().getGateway().getSubDeviceThing(mBaseInfo).first;
// if (thing == null){
// showToast("子设备当前状态不支持");
// return;
// }
// thing.thingPropertyPost(reportData, resourceListener);
} catch (Exception e) {
e.printStackTrace();
showToast("上报失败 " + e);
}
}
}

/**
* 上报返回数据
*/
private static IPublishResourceListener resourceListener = new IPublishResourceListener() {
@Override
public void onSuccess(String alinkId, Object o) {
AppLog.d(TAG, "onSuccess() called with: alinkId = [" + alinkId + "], o = [" + o + "]");
showToast("设备状态上报上行成功(code=200),用户可以根据云端返回的data判断是否有不符合的属性上报");
}

@Override
public void onError(String alinkId, AError aError) {
AppLog.d(TAG, "onError() called with: alinkId = [" + alinkId + "], aError = [" + aError + "]");
showToast("设备上报状态失败");
}
};

/**
* 接收到服务
*/
private static ITResRequestHandler itResRequestHandler=new ITResRequestHandler() {
@Override
public void onProcess(String identify, Object result, ITResResponseCallback itResResponseCallback) {
Log.d(TAG, "onProcess() called with: s = [" + identify + "], o = [" + result + "], itResResponseCallback = [" + itResResponseCallback + "]");
showToast("收到异步服务调用 " + identify);
if (SERVICE_SET.equals(identify)) {
// TODO 用户按照真实设备的接口调用 设置设备的属性
// 设置完真实设备属性之后,上报设置完成的属性值
// 用户根据实际情况判断属性是否设置成功 这里测试直接返回成功
boolean isSetPropertySuccess = true;
if (isSetPropertySuccess){
if (result instanceof InputParams) {
Map<String, ValueWrapper> data = (Map<String, ValueWrapper>) ((InputParams) result).getData();
// data.get()

// 响应云端 接收数据成功
itResResponseCallback.onComplete(identify, null, null);
} else {
itResResponseCallback.onComplete(identify, null, null);
}
//updatePropertyValue((Property) mPropertySpinner.getSelectedItem());
} else {
AError error = new AError();
error.setCode(100);
error.setMsg("setPropertyFailed.");
itResResponseCallback.onComplete(identify, new ErrorInfo(error), null);
}

} else if (SERVICE_GET.equals(identify)){
// 初始化的时候将默认值初始化传进来,物模型内部会直接返回云端缓存的值

}else
{
OutputParams outputParams = new OutputParams();
// outputParams.put("op", new ValueWrapper.IntValueWrapper(20));
itResResponseCallback.onComplete(identify,null, outputParams);
}
}

@Override
public void onSuccess(Object o, OutputParams outputParams) {
showToast("注册服务成功");
}

@Override
public void onFail(Object o, ErrorInfo errorInfo) {
showToast("注册服务失败");
}
};
//endregion
}

+ 24
- 0
app/src/main/java/com/bonait/bnframework/common/iot/manager/IDemoCallback.java View File

@@ -0,0 +1,24 @@
package com.bonait.bnframework.common.iot.manager;

import com.aliyun.alink.linkkit.api.ILinkKitConnectListener;

/*
* Copyright (c) 2014-2016 Alibaba Group. All rights reserved.
* License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

public interface IDemoCallback extends ILinkKitConnectListener{
}

+ 330
- 0
app/src/main/java/com/bonait/bnframework/common/iot/manager/InitManager.java View File

@@ -0,0 +1,330 @@
package com.bonait.bnframework.common.iot.manager;

import android.content.Context;
import android.text.TextUtils;

import com.alibaba.fastjson.JSONObject;
import com.aliyun.alink.dm.api.DeviceInfo;
import com.aliyun.alink.dm.api.IoTApiClientConfig;
import com.aliyun.alink.linkkit.api.ILinkKitConnectListener;
import com.aliyun.alink.linkkit.api.IoTDMConfig;
import com.aliyun.alink.linkkit.api.IoTH2Config;
import com.aliyun.alink.linkkit.api.IoTMqttClientConfig;
import com.aliyun.alink.linkkit.api.LinkKit;
import com.aliyun.alink.linkkit.api.LinkKitInitParams;
import com.aliyun.alink.linksdk.channel.core.persistent.mqtt.MqttConfigure;
import com.aliyun.alink.linksdk.cmp.api.ConnectSDK;
import com.aliyun.alink.linksdk.cmp.connect.channel.MqttPublishRequest;
import com.aliyun.alink.linksdk.cmp.connect.hubapi.HubApiRequest;
import com.aliyun.alink.linksdk.cmp.core.base.AMessage;
import com.aliyun.alink.linksdk.cmp.core.base.ARequest;
import com.aliyun.alink.linksdk.cmp.core.base.AResponse;
import com.aliyun.alink.linksdk.cmp.core.base.ConnectState;
import com.aliyun.alink.linksdk.cmp.core.listener.IConnectNotifyListener;
import com.aliyun.alink.linksdk.cmp.core.listener.IConnectSendListener;
import com.aliyun.alink.linksdk.tmp.device.payload.ValueWrapper;
import com.aliyun.alink.linksdk.tools.AError;
import com.bonait.bnframework.common.iot.AliyunIOTManager;
import com.bonait.bnframework.common.iot.mode.AppLog;

import java.util.HashMap;
import java.util.Map;

/*
* Copyright (c) 2014-2016 Alibaba Group. All rights reserved.
* License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

public class InitManager {
private static final String TAG = "InitManager";

/**
* 如果需要动态注册设备获取设备的deviceSecret, 可以参考本接口实现。
* 动态注册条件检测:
* 1.云端开启该设备动态注册功能;
* 2.首先在云端创建 pk,dn;
* @param context 上下文
* @param productKey 产品类型
* @param deviceName 设备名称 需要现在云端创建
* @param productSecret 产品密钥
* @param listener 密钥请求回调
*/
public static void registerDevice(Context context, String productKey, String deviceName, String productSecret, IConnectSendListener listener) {
DeviceInfo myDeviceInfo = new DeviceInfo();
myDeviceInfo.productKey = productKey;
myDeviceInfo.deviceName = deviceName;
myDeviceInfo.productSecret = productSecret;
LinkKitInitParams params = new LinkKitInitParams();
params.connectConfig = new IoTApiClientConfig();
// 如果明确需要切换域名,可以设置 connectConfig 中 domain 的值;
params.deviceInfo = myDeviceInfo;
HubApiRequest hubApiRequest = new HubApiRequest();
hubApiRequest.path = "/auth/register/device";
// 调用动态注册接口
LinkKit.getInstance().deviceRegister(context, params, hubApiRequest, listener);
}

/**
* Android 设备端 SDK 初始化示例代码
* @param context 上下文
* @param productKey 产品类型
* @param deviceName 设备名称
* @param deviceSecret 设备密钥
* @param productSecret 产品密钥
* @param callback 初始化建联结果回调
*/
public static void init(final Context context, String productKey, String deviceName, String deviceSecret, String productSecret, String mqttHost, final IDemoCallback callback) {
final LinkKitInitParams params = new LinkKitInitParams();

//Step1: 构造三元组信息对象
DeviceInfo deviceInfo = new DeviceInfo();
deviceInfo.productKey = productKey; // 产品类型
deviceInfo.deviceName = deviceName; // 设备名称
deviceInfo.deviceSecret = deviceSecret; // 设备密钥
deviceInfo.productSecret = productSecret; // 产品密钥
params.deviceInfo = deviceInfo;

//Step2: 全局默认域名
IoTApiClientConfig userData = new IoTApiClientConfig();
params.connectConfig = userData;

//Step3: 物模型缓存
Map<String, ValueWrapper> propertyValues = new HashMap<>();
/**
* 物模型的数据会缓存到该字段中. 不可删除或者设置为空, 否则功能会异常
* 用户调用物模型上报接口之后,物模型会有相关数据缓存。
*/
params.propertyValues = propertyValues;

//Step4: mqtt设置
/**
* 慎用
* Mqtt 相关参数设置,包括接入点等信息.具体见deviceinfo文件说明
* 域名、产品密钥、认证安全模式等;
*/
IoTMqttClientConfig clientConfig = new IoTMqttClientConfig(productKey, deviceName, deviceSecret);
clientConfig.receiveOfflineMsg = false;//cleanSession=1 不接受离线消息
//mqtt接入点信息. 详情请参照https://help.aliyun.com/document_detail/147356.htm
clientConfig.channelHost = mqttHost;
params.mqttClientConfig = clientConfig;

//Step5: 高阶功能功能配置,默认均为关闭状态
IoTDMConfig ioTDMConfig = new IoTDMConfig();
// 默认开启物模型功能,开启之后init方法会等到物模型初始化(包含请求云端物模型)完成之后才返回onInitDone
ioTDMConfig.enableThingModel = true;
// 默认不开启网关功能,开启之后,初始化的时候会初始化网关模块,获取云端网关子设备列表
ioTDMConfig.enableGateway = false;
// 默认不开启,是否开启日志推送功能
ioTDMConfig.enableLogPush = false;
params.ioTDMConfig = ioTDMConfig;

//Step6: 下行消息处理回调设置
LinkKit.getInstance().registerOnPushListener(notifyListener);

//Step7: 一型一密免预注册设置(可选)
//对于一型一密免预注册的设备, 设备连云时要用上deviceToken和clientId
MqttConfigure.deviceToken = AliyunIOTManager.deviceToken;
MqttConfigure.clientId = AliyunIOTManager.clientId;

//Step8: H2文件上传设置(可选)
/**
* 如果要用到HTTP2文件上传, 需要用户设置域名
*/
IoTH2Config ioTH2Config = new IoTH2Config();
ioTH2Config.clientId = "client-id";
ioTH2Config.endPoint = "https://" + productKey + ioTH2Config.endPoint;// 线上环境
params.iotH2InitParams = ioTH2Config;

//Step9: id2相关设置(可选)
/**
* 如果要用到id2的方式鉴权, 请确认在id2控制台开启相关服务后, 再打开下列代码
* 同时,在./app/src/main/res/raw/deviceinfo中,将deviceSecret设置为itls_secret,并填入productSecret
*/
// Id2ItlsSdk.init(context);
// if ("itls_secret".equals(deviceSecret)){
// clientConfig.channelHost = productKey + ".itls.cn-shanghai.aliyuncs.com:1883";//线上
// clientConfig.productSecret = productSecret;
// clientConfig.secureMode = 8;

// 对于对于企业实例, 或者2021年07月30日之后(含当日)开通的物联网平台服务下公共实例的客户,需要通过如下方式指定实例id(格式如iot-xxxxxx)
// MqttConfigure.extraMqttClientIdItems=",instanceId=" + "${实例id}";
// }

/**
* 设备初始化建联
* onError 初始化建联失败,如果因网络问题导致初始化失败,需要用户重试初始化
* onInitDone 初始化成功
*/
LinkKit.getInstance().init(context, params, new ILinkKitConnectListener() {
@Override
public void onError(AError error) {
AppLog.d(TAG, "onError() called with: error = [" + getAErrorString(error) + "]");
callback.onError(error);
}

@Override
public void onInitDone(Object data) {
AppLog.d(TAG, "onInitDone() called with: data = [" + data + "]");
callback.onInitDone(data);
}
});
}

/**
* 下行监听器,云端 MQTT 下行数据都会通过这里回调
*/
private static IConnectNotifyListener notifyListener = new IConnectNotifyListener() {
/**
* onNotify 会触发的前提是 shouldHandle 没有指定不处理这个topic
* @param connectId 连接类型,这里判断是否长链 connectId == ConnectSDK.getInstance().getPersistentConnectId()
* @param topic 下行的topic
* @param aMessage 下行的数据内容
*/
@Override
public void onNotify(String connectId, String topic, AMessage aMessage) {
String data = new String((byte[]) aMessage.data);
// 服务端返回数据示例 data = {"method":"thing.service.test_service","id":"123374967","params":{"vv":60},"version":"1.0.0"}
AppLog.d(TAG, "onNotify() called with: connectId = [" + connectId + "], topic = [" + topic + "], aMessage = [" + data + "]");

if (ConnectSDK.getInstance().getPersistentConnectId().equals(connectId) && !TextUtils.isEmpty(topic) &&
topic.startsWith("/ext/rrpc/")) {
ToastUtils.showToast("收到云端自定义RRPC下行:topic=" + topic + ",data=" + data);
//示例 topic=/ext/rrpc/1138654706478941696//a1ExY4afKY1/testDevice/user/get
//AppLog.d(TAG, "receice Message=" + new String((byte[]) aMessage.data));
// 服务端返回数据示例 {"method":"thing.service.test_service","id":"123374967","params":{"vv":60},"version":"1.0.0"}
MqttPublishRequest request = new MqttPublishRequest();
request.isRPC = false;
request.topic = topic;
String[] array = topic.split("/");
String resId = array[3];
request.msgId = resId;

String alinkdId = null;

try{
JSONObject jsonObject = JSONObject.parseObject(data);
alinkdId = jsonObject.getString("id");
}catch (Exception e){
AppLog.e(TAG,"parse alinkId failed, exit");
return;
}

// TODO 用户根据实际情况填写 仅做参考
request.payloadObj = "{\"id\":\"" + alinkdId + "\", \"code\":\"200\"" + ",\"data\":{\"aa\":1} }";
LinkKit.getInstance().publish(request, new IConnectSendListener() {
@Override
public void onResponse(ARequest aRequest, AResponse aResponse) {
// 响应成功
// ToastUtils.showToast("云端系统RRPC下行响应成功");
}

@Override
public void onFailure(ARequest aRequest, AError aError) {
// 响应失败
// ToastUtils.showToast("云端系统RRPC下行响应失败");
}
});
} else if (ConnectSDK.getInstance().getPersistentConnectId().equals(connectId) && !TextUtils.isEmpty(topic) &&
topic.startsWith("/sys/" + AliyunIOTManager.productKey + "/" + AliyunIOTManager.deviceName + "/rrpc/request/")) {
ToastUtils.showToast("收到云端系统RRPC下行:topic=" + topic + ",data=" + data);
// AppLog.d(TAG, "receice Message=" + new String((byte[]) aMessage.data));
// 服务端返回数据示例 {"method":"thing.service.test_service","id":"123374967","params":{"vv":60},"version":"1.0.0"}
MqttPublishRequest request = new MqttPublishRequest();
// 支持 0 和 1, 默认0
// request.qos = 0;
request.isRPC = false;
request.topic = topic.replace("request", "response");
String[] array = topic.split("/");
String resId = array[6];
request.msgId = resId;
// TODO 用户根据实际情况填写 仅做参考
request.payloadObj = "{\"id\":\"" + resId + "\", \"code\":\"200\"" + ",\"data\":{} }";

LinkKit.getInstance().publish(request, new IConnectSendListener() {
@Override
public void onResponse(ARequest aRequest, AResponse aResponse) {
// ToastUtils.showToast("云端系统RRPC下行响应成功");
}

@Override
public void onFailure(ARequest aRequest, AError aError) {
// ToastUtils.showToast("云端系统RRPC下行响应失败");
}
});
} else if (ConnectSDK.getInstance().getPersistentConnectId().equals(connectId) && !TextUtils.isEmpty(topic) &&
topic.startsWith("/sys/" + AliyunIOTManager.productKey + "/" + AliyunIOTManager.deviceName + "/broadcast/request/")) {
/**
* topic 格式:/sys/${pk}/${dn}/broadcast/request/+
* 无需订阅,云端免订阅,默认无需业务进行ack,但是也支持用户云端和设备端约定业务ack
* 示例:/sys/a14NQ5RLiZA/android_lp_test1/broadcast/request/1229336863924294656
* 注意:触发端数据需要进行Base64编码,否则会出现端上乱码,
* 如云端: org.apache.commons.codec.binary.Base64.encodeBase64String("broadcastContent".getBytes())
*/
//
ToastUtils.showToast("收到云端批量广播下行:topic=" + topic + ",data=" + data);
//TODO 根据批量广播做业务逻辑处理

} else if (ConnectSDK.getInstance().getPersistentConnectId().equals(connectId) && !TextUtils.isEmpty(topic) &&
topic.startsWith("/broadcast/" + AliyunIOTManager.productKey )) {
//
/**
* topic 需要用户自己订阅才能收到,topic 格式:/broadcast/${pk}/${自定义action},需要和云端发送topic一致
* 示例:/broadcast/a14NQ5RLiZA/oldBroadcast
* 注意:触发端数据需要进行Base64编码,否则会出现端上乱码,
* 如云端: org.apache.commons.codec.binary.Base64.encodeBase64String("broadcastContent".getBytes())
*/
ToastUtils.showToast("收到云端广播下行:topic=" + topic + ",data=" + data);
//TODO 根据广播做业务逻辑处理
} else {
ToastUtils.showToast("收到云端下行:topic=" + topic + ",data=" + data);
/**
* TODO
* 根据订阅的具体 topic 做业务处理
*/
}
}

/**
* @param connectId 连接类型,这里判断是否长链 connectId == ConnectSDK.getInstance().getPersistentConnectId()
* @param topic 下行topic
* @return 是否要处理这个topic,如果为true,则会回调到onNotify;如果为false,onNotify不会回调这个topic相关的数据。建议默认为true。
*/
@Override
public boolean shouldHandle(String connectId, String topic) {
return true;
}

/**
* @param connectId 连接类型,这里判断是否长链 connectId == ConnectSDK.getInstance().getPersistentConnectId()
* @param connectState {@link ConnectState}
* CONNECTED, 连接成功
* DISCONNECTED, 已断链
* CONNECTING, 连接中
* CONNECTFAIL; 连接失败
*/
@Override
public void onConnectStateChange(String connectId, ConnectState connectState) {
AppLog.d(TAG, "onConnectStateChange() called with: connectId = [" + connectId + "], connectState = [" + connectState + "]");
}
};

public static String getAErrorString(AError error) {
if (error == null) {
return null;
}
return JSONObject.toJSONString(error);
}
}

+ 71
- 0
app/src/main/java/com/bonait/bnframework/common/iot/manager/MD5Util.java View File

@@ -0,0 +1,71 @@
package com.bonait.bnframework.common.iot.manager;

import android.text.TextUtils;

import com.bonait.bnframework.common.iot.mode.AppLog;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;

public class MD5Util {
private static final String TAG = "MD5Util";

public static String getFileMd5(String filepath) {
if (TextUtils.isEmpty(filepath)) {
AppLog.e(TAG, "getMd5ByFile filepath=null.");
return null;
}

File file = null;
try {
file = new File(filepath);
} catch (Exception e) {
e.printStackTrace();
}
if (file == null) {
AppLog.e(TAG, "getMd5ByFile file not exist.");
return null;
}
InputStream inputStream = null;
MessageDigest md5 = null;

byte[] buffer = new byte[1024 * 8];
int readCount = 0;

try {
inputStream = new FileInputStream(file);
md5 = MessageDigest.getInstance("MD5");
while ((readCount = inputStream.read(buffer)) > 0) {
md5.update(buffer, 0, readCount);
}
return hexString(md5.digest());
} catch (Exception e) {
System.out.println("error");
return null;
} finally {
try {
if (inputStream != null) {
inputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}

public static String hexString(byte[] md5Bytes) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < md5Bytes.length; i++) {
int val = ((int) md5Bytes[i]) & 0xff;
if (val < 16) {
sb.append("0");
}
sb.append(Integer.toHexString(val));
}
return sb.toString();
}

}

+ 25
- 0
app/src/main/java/com/bonait/bnframework/common/iot/manager/ToastUtils.java View File

@@ -0,0 +1,25 @@
package com.bonait.bnframework.common.iot.manager;

import android.content.Context;
import android.widget.Toast;

import com.aliyun.alink.linksdk.tools.ThreadTools;
import com.bonait.bnframework.MainApplication;
import com.bonait.bnframework.common.iot.mode.AppLog;

public class ToastUtils {

public static void showToast(String message) {
AppLog.e("客户端接收阿里云数据",message);
showToast(message, MainApplication.getContext());
}

private static void showToast(final String message, final Context context) {
ThreadTools.runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
}
});
}
}

+ 56
- 0
app/src/main/java/com/bonait/bnframework/common/iot/mode/AppLog.java View File

@@ -0,0 +1,56 @@
package com.bonait.bnframework.common.iot.mode;

import android.util.Log;

import com.aliyun.alink.linksdk.tools.log.HLoggerFactory;
import com.aliyun.alink.linksdk.tools.log.ILogger;


public class AppLog {
private static final String PRE_TAG = "LK--";
private static ILogger logger = new HLoggerFactory().getInstance(PRE_TAG);

public static final int ASSERT = Log.ASSERT;
public static final int DEBUG = Log.DEBUG;
public static final int ERROR = Log.ERROR;
public static final int INFO = Log.INFO;
public static final int VERBOSE = Log.VERBOSE;
public static final int WARN = Log.WARN;

static public void d(String tag, String msg) {
logger.d(tag, getFilterString(msg));
}

static public void i(String tag, String msg) {
logger.i(tag, getFilterString(msg));
}

static public void w(String tag, String msg) {
logger.w(tag, getFilterString(msg));
}

static public void e(String tag, String msg) {
logger.e(tag, getFilterString(msg));
}

static public void e(String tag, String where, Exception ex) {
if (null != ex) {
logger.e(tag, getFilterString(where) + " EXCEPTION: " + ex.getMessage());
ex.printStackTrace();
} else {
logger.e(tag, getFilterString(where) + " EXCEPTION: unknown");
}
}

public static void llog(byte priority, String tag, String msg) {
com.aliyun.alink.linksdk.tools.ALog.llog(priority, PRE_TAG + tag, getFilterString(msg));
}

public static void setLevel(byte level) {
com.aliyun.alink.linksdk.tools.ALog.setLevel(level);
}

private static String getFilterString(String msg) {
return msg;
}
}

+ 58
- 0
app/src/main/java/com/bonait/bnframework/common/iot/mode/DeviceInfoData.java View File

@@ -0,0 +1,58 @@
package com.bonait.bnframework.common.iot.mode;

import com.aliyun.alink.dm.api.DeviceInfo;

import java.util.List;

/*
* Copyright (c) 2014-2016 Alibaba Group. All rights reserved.
* License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

public class DeviceInfoData extends DeviceInfo {

/**
* 与网关关联的子设备信息
* 后续网关测试demo 会 添加子设备 删除子设备 建立 topo关系 子设备上下线等
*/
public List<DeviceInfo> subDevice = null;
public String password = null;
public String username = null;
public String clientId = null;

//旧公共分区, pk.region; 无instanceId
//新公共实例, 企业实例,下述都有
//todo 重点说明一下
public String mqttHost = null;
public String instanceId = null;

/**
* 动态注册类型
*/
public String registerType = null;
public String deviceToken = null;

@Override
public String toString() {
return "DeviceInfoData{" +
"subDevice=" + subDevice +
", password='" + password + '\'' +
", username='" + username + '\'' +
", clientId='" + clientId + '\'' +
", deviceToken='" + deviceToken + '\'' +
'}';
}
}

+ 4
- 0
app/src/main/java/com/bonait/bnframework/modules/home/activity/BottomNavigation2Activity.java View File

@@ -4,6 +4,7 @@ import android.os.Bundle;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;


import com.bonait.bnframework.business.ConfigData; import com.bonait.bnframework.business.ConfigData;
import com.bonait.bnframework.common.iot.AliyunIOTManager;
import com.google.android.material.bottomnavigation.BottomNavigationView; import com.google.android.material.bottomnavigation.BottomNavigationView;
import androidx.viewpager.widget.ViewPager; import androidx.viewpager.widget.ViewPager;
import android.view.KeyEvent; import android.view.KeyEvent;
@@ -54,6 +55,7 @@ public class BottomNavigation2Activity extends BaseActivity {
@Override @Override
protected void onDestroy() { protected void onDestroy() {
ConfigData.getInstance().ColsePLC(); ConfigData.getInstance().ColsePLC();
//AliyunIOTManager.getInstance().CloseDev();
super.onDestroy(); super.onDestroy();
} }


@@ -159,5 +161,7 @@ public class BottomNavigation2Activity extends BaseActivity {
ConfigData.getInstance().ToggleEnvironment(); ConfigData.getInstance().ToggleEnvironment();
//2.初始化PLC //2.初始化PLC
ConfigData.getInstance().ConnectPLC(); ConfigData.getInstance().ConnectPLC();
//初始化阿里云连接
//AliyunIOTManager.getInstance().OpenDev(this);
} }
} }

+ 6
- 0
app/src/main/java/com/bonait/bnframework/modules/home/fragment/Home1Fragment.java View File

@@ -23,6 +23,8 @@ import android.widget.ImageView;
import android.widget.RelativeLayout; import android.widget.RelativeLayout;
import android.widget.SeekBar; import android.widget.SeekBar;


import com.aliyun.alink.linksdk.tmp.devicemodel.Event;
import com.aliyun.alink.linksdk.tmp.devicemodel.Property;
import com.bonait.bnframework.R; import com.bonait.bnframework.R;
import com.bonait.bnframework.business.ExecuteTheRecipe; import com.bonait.bnframework.business.ExecuteTheRecipe;
import com.bonait.bnframework.common.base.BaseFragment; import com.bonait.bnframework.common.base.BaseFragment;
@@ -36,6 +38,7 @@ import com.bonait.bnframework.common.helper.ByteHelper;
import com.bonait.bnframework.common.helper.I.IThread; import com.bonait.bnframework.common.helper.I.IThread;
import com.bonait.bnframework.common.helper.I.IWriteCallBack; import com.bonait.bnframework.common.helper.I.IWriteCallBack;
import com.bonait.bnframework.common.helper.I.MyClickListener; import com.bonait.bnframework.common.helper.I.MyClickListener;
import com.bonait.bnframework.common.helper.Json;
import com.bonait.bnframework.common.helper.MessageLog; import com.bonait.bnframework.common.helper.MessageLog;
import com.bonait.bnframework.common.helper.ThreadManager; import com.bonait.bnframework.common.helper.ThreadManager;
import com.bonait.bnframework.common.modbus.ModbusTcpServer; import com.bonait.bnframework.common.modbus.ModbusTcpServer;
@@ -52,6 +55,7 @@ import com.capton.colorfulprogressbar.ColorfulProgressbar;
import com.litao.slider.NiftySlider; import com.litao.slider.NiftySlider;
import com.litao.slider.SliderEffect; import com.litao.slider.SliderEffect;
import com.litao.slider.Utils; import com.litao.slider.Utils;
import com.lzy.okgo.OkGo;
import com.orhanobut.logger.Logger; import com.orhanobut.logger.Logger;
import com.qmuiteam.qmui.widget.QMUITopBar; import com.qmuiteam.qmui.widget.QMUITopBar;
import com.qmuiteam.qmui.widget.dialog.QMUIDialog; import com.qmuiteam.qmui.widget.dialog.QMUIDialog;
@@ -642,6 +646,8 @@ public class Home1Fragment extends BaseFragment {
if (!IsMake(true)) { return; } if (!IsMake(true)) { return; }
ToastUtils.info("点击按钮:急停"); ToastUtils.info("点击按钮:急停");
ExecuteTheRecipe.WritePLC("停止", true, null); ExecuteTheRecipe.WritePLC("停止", true, null);


break; break;
} }
} }


+ 70
- 0
app/src/main/res/raw/deviceinfo View File

@@ -0,0 +1,70 @@
{
/**
* 物联网平台为产品颁发的全局唯一标识符
*/
"productKey": "grgpECHSL7q",

/**
* 设备在产品内的唯一标识符
*/
"deviceName": "fyfcs",

/**
* 产品秘钥,一型一密(预注册/免预注册)的情况下需要填入,否则为空
*/
"productSecret": "k5etVQigsmaSxz9r",

/**
* 物联网平台为设备颁发的设备密钥,用于认证加密. 一机一密情况下需要填入, 否则为空
*/
"deviceSecret": "1974cc749f4b10aa2f48a01e2f316ea6",

/**
* 如果productSecret不为空,但deviceSecret为空,表明设备采用一型一密方式进行认证
* registerType表示一型一密的类型: 输入空字符串"", 表示预注册; 输入regnwl, 表示免预注册
* 默认(不填)为预注册.
*/
"registerType": "",

/**
* 设置实例的实例id.
* 使用公共/企业实例接入的客户, 如果实例详情有实例的id, 需要将该实例id填入.默认为空.
* 格式如 iot-0****l
*/
"instanceId": "iot-06z00g9pf3kwtxp",

/**
* 对于企业实例, 或者2021年07月30日之后(含当日)开通的物联网平台服务下公共实例, 请使用带实例id的url接入,
* 使用公共/企业实例接入的客户, 如果实例详情中带有接入点信息, 也可以用该接入点接入. 实例接入点的参考格式如:
* "{instanceid}.mqtt.iothub.aliyuncs.com:443"
*
* 对于2021年07月30日之前(不含当日)开通的物联网平台服务下公共实例,
* 实例接入点的格式如: "{YourProductKey}.iot-as-mqtt.{region}.aliyuncs.com:443" ,
* region默认cn-shanghai, 如果用户的region属于上海, 请不要再设置. 否则, 请在如下域名中选择
* | ${YourProductKey}.iot-as-mqtt.cn-shanghai.aliyuncs.com | Shanghai | 443
* | ${YourProductKey}.iot-as-mqtt.ap-southeast-1.aliyuncs.com | Singapore | 443
* | ${YourProductKey}.iot-as-mqtt.ap-northeast-1.aliyuncs.com | Japan | 443
* | ${YourProductKey}.iot-as-mqtt.us-west-1.aliyuncs.com | West-US | 443
* | ${YourProductKey}.iot-as-mqtt.eu-central-1.aliyuncs.com | EU | 443
* 注:北京/深圳region的用户,请参照上文的企业实例填入接入点,不要用本段提到的带region信息的接入点
*
* 详情请参照https://help.aliyun.com/document_detail/147356.htm
*/
"mqttHost": "",

/**
* 网关/子设备连云情况下需要填写.默认为空.
*/
"subDevice": [
{
"productKey": "",
"productSecret": "",
"deviceName": ""
},
{
"productKey": "",
"productSecret": "",
"deviceName": ""
}
]
}

+ 6
- 2
build.gradle View File

@@ -5,7 +5,9 @@ buildscript {
repositories { repositories {
google() google()
jcenter() jcenter()

maven {
url "https://maven.aliyun.com/nexus/content/repositories/releases/"
}
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:7.4.1' classpath 'com.android.tools.build:gradle:7.4.1'
@@ -21,7 +23,9 @@ allprojects {
google() google()
jcenter() jcenter()
maven { url "https://jitpack.io" } maven { url "https://jitpack.io" }

maven {
url "https://maven.aliyun.com/nexus/content/repositories/releases/"
}
} }
} }




Loading…
Cancel
Save