Skip to content

Commit c611098

Browse files
committed
Merge branch 'feature/matter_controller_remote_api_support' into 'master'
Added support for controlling matter-only devices remotely via controller. See merge request app-frameworks/esp-rainmaker-android!82
2 parents 21753df + 0a06cf6 commit c611098

15 files changed

+1544
-287
lines changed

app/build.gradle

+2-2
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@ android {
5555
applicationId "com.espressif.rainmaker"
5656
minSdkVersion 27
5757
targetSdkVersion 34
58-
versionCode 117
59-
versionName "3.2.4 - ${getGitHash()}"
58+
versionCode 119
59+
versionName "3.3.0 - ${getGitHash()}"
6060
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
6161

6262
buildConfigField "String", "GitHash", "\"${getGitHash()}\""

app/src/main/java/com/espressif/AppConstants.kt

+12
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ class AppConstants {
7373
const val SERVICE_TYPE_TIME = "esp.service.time"
7474
const val SERVICE_TYPE_LOCAL_CONTROL = "esp.service.local_control"
7575
const val SERVICE_TYPE_SYSTEM = "esp.service.system"
76+
const val SERVICE_TYPE_MATTER_CONTROLLER = "esp.service.matter-controller"
7677

7778
// Param Types
7879
const val PARAM_TYPE_NAME = "esp.param.name"
@@ -89,6 +90,9 @@ class AppConstants {
8990
const val PARAM_TYPE_REBOOT = "esp.param.reboot"
9091
const val PARAM_TYPE_FACTORY_RESET = "esp.param.factory-reset"
9192
const val PARAM_TYPE_WIFI_RESET = "esp.param.wifi-reset"
93+
const val PARAM_TYPE_MATTER_DEVICES = "esp.param.matter-devices"
94+
const val PARAM_TYPE_MATTER_CTRL_DATA_VERSION =
95+
"esp.param.matter-controller-data-version"
9296

9397
// Param names
9498
const val PARAM_POWER = "Power"
@@ -345,6 +349,8 @@ class AppConstants {
345349
const val KEY_AUTOMATION = "automation"
346350
const val KEY_LOAD_AUTOMATION_PAGE = "load_automation"
347351
const val KEY_SYSTEM = "System"
352+
const val KEY_MATTER_CONTROLLER = "Matter-Controller"
353+
const val KEY_REACHABLE = "reachable"
348354

349355
const val KEY_OPERATION = "operation"
350356
const val KEY_OPERATION_ADD = "add"
@@ -461,6 +467,12 @@ class AppConstants {
461467
const val PRIVILEGE_ADMIN = 5
462468
const val PRIVILEGE_OPERATE = 3
463469

470+
const val NODE_STATUS_OFFLINE = 1;
471+
const val NODE_STATUS_ONLINE = 2;
472+
const val NODE_STATUS_LOCAL = 3;
473+
const val NODE_STATUS_MATTER_LOCAL = 4;
474+
const val NODE_STATUS_REMOTELY_CONTROLLABLE = 5;
475+
464476
enum class UpdateEventType {
465477
EVENT_DEVICE_ADDED,
466478
EVENT_DEVICE_REMOVED,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// Copyright 2024 Espressif Systems (Shanghai) PTE LTD
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package com.espressif
16+
17+
class ESPControllerAPIKeys {
18+
19+
companion object {
20+
21+
const val KEY_MATTER_CONTROLLER = "matter-controller"
22+
const val KEY_MATTER_CONTROLLER_DATA_VERSION = "matter-controller-data-version"
23+
const val KEY_MATTER_CONTROLLER_DATA = "matter-controller-data"
24+
const val KEY_DATA = "data"
25+
const val KEY_ENABLED = "enabled"
26+
const val KEY_REACHABLE = "reachable"
27+
const val KEY_MATTER_NODES = "matter-nodes"
28+
const val KEY_MATTER_NODE_ID = "matter-node-id"
29+
const val KEY_ENDPOINTS = "endpoints"
30+
const val KEY_ENDPOINT_ID = "endpoint-id"
31+
const val KEY_CLUSTERS = "clusters"
32+
const val KEY_CLUSTER_ID = "cluster-id"
33+
const val KEY_COMMANDS = "commands"
34+
const val KEY_COMMAND_ID = "command-id"
35+
36+
const val ENDPOINT_ID_1 = "0x1"
37+
38+
const val CLUSTER_ID_ON_OFF = "0x6"
39+
const val CLUSTER_ID_LEVEL_CONTROL = "0x8"
40+
const val CLUSTER_ID_COLOR_CONTROL = "0x300"
41+
const val CLUSTER_ID_THERMOSTAT = "0x201"
42+
const val CLUSTER_ID_TEMPERATURE_MEASUREMENT = "0x402"
43+
44+
const val COMMAND_ID_OFF = "0x0"
45+
const val COMMAND_ID_ON = "0x1"
46+
const val COMMAND_ID_TOGGLE = "0x2"
47+
const val COMMAND_ID_MOVE_TO_LEVEL_WITH_ON_OFF = "0x0"
48+
const val COMMAND_ID_MOVE_TO_SATURATION = "0x3"
49+
const val COMMAND_ID_MOVE_TO_HUE = "0x0"
50+
51+
const val ATTRIBUTE_ID_ON_OFF = "0x0"
52+
const val ATTRIBUTE_ID_BRIGHTNESS_LEVEL = "0x0"
53+
const val ATTRIBUTE_ID_CURRENT_HUE = "0x0"
54+
const val ATTRIBUTE_ID_CURRENT_SATURATION = "0x1"
55+
const val ATTRIBUTE_ID_LOCAL_TEMPERATURE = "0x0"
56+
const val ATTRIBUTE_ID_SYSTEM_MODE = "0x1c"
57+
const val ATTRIBUTE_ID_OCCUPIED_COOLING_SETPOINT = "0x11"
58+
const val ATTRIBUTE_ID_OCCUPIED_HEATING_SETPOINT = "0x12"
59+
const val ATTRIBUTE_ID_MEASURED_TEMPERATURE = "0x0"
60+
}
61+
}

app/src/main/java/com/espressif/EspApplication.java

+58-1
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@
8383
import java.security.cert.Certificate;
8484
import java.security.cert.CertificateException;
8585
import java.util.ArrayList;
86+
import java.util.Arrays;
8687
import java.util.Base64;
8788
import java.util.HashMap;
8889
import java.util.Iterator;
@@ -116,6 +117,7 @@ public class EspApplication extends Application {
116117
public HashMap<String, ChipClient> chipClientMap;
117118
public HashMap<String, List<DeviceMatterInfo>> matterDeviceInfoMap;
118119
public ArrayList<String> availableMatterDevices;
120+
public HashMap<String, HashMap<String, String>> controllerDevices;
119121
public EspOtaUpdate otaUpdateInfo;
120122

121123
private SharedPreferences appPreferences;
@@ -149,6 +151,7 @@ public void onCreate() {
149151
chipClientMap = new HashMap<>();
150152
matterDeviceInfoMap = new HashMap<>();
151153
availableMatterDevices = new ArrayList<>();
154+
controllerDevices = new HashMap<>();
152155

153156
appPreferences = getSharedPreferences(AppConstants.ESP_PREFERENCES, Context.MODE_PRIVATE);
154157
BASE_URL = appPreferences.getString(AppConstants.KEY_BASE_URL, BuildConfig.BASE_URL);
@@ -215,7 +218,11 @@ public void changeAppState(AppState newState, Bundle extras) {
215218
if (!chipClientMap.containsKey(matterNodeId)) {
216219
clientHelper.initChipClientInBackground(matterNodeId);
217220
} else {
218-
clientHelper.getCurrentValues(nodeId, matterNodeId, nodeMap.get(nodeId));
221+
try {
222+
clientHelper.getCurrentValues(nodeId, matterNodeId, nodeMap.get(nodeId));
223+
} catch (ExecutionException e) {
224+
e.printStackTrace();
225+
}
219226
}
220227
}
221228
break;
@@ -529,6 +536,7 @@ public void onSuccess(Bundle data) {
529536
}
530537
}
531538
}
539+
setRemoteDeviceStatus();
532540
changeAppState(AppState.GET_DATA_SUCCESS, null);
533541
}
534542

@@ -544,6 +552,49 @@ public void onNetworkFailure(Exception exception) {
544552
});
545553
}
546554

555+
private void setRemoteDeviceStatus() {
556+
557+
for (Map.Entry<String, HashMap<String, String>> entry : controllerDevices.entrySet()) {
558+
559+
String controllerNodeId = entry.getKey();
560+
HashMap<String, String> matterOnlyDevices = entry.getValue();
561+
562+
for (Map.Entry<String, String> controllerDevice : matterOnlyDevices.entrySet()) {
563+
String matterDeviceId = controllerDevice.getKey();
564+
String jsonStr = controllerDevice.getValue();
565+
566+
if (jsonStr != null) {
567+
try {
568+
JSONObject deviceJson = new JSONObject(jsonStr);
569+
boolean enabled = deviceJson.optBoolean(AppConstants.KEY_ENABLED);
570+
boolean reachable = deviceJson.optBoolean(AppConstants.KEY_REACHABLE);
571+
572+
if (enabled && reachable) {
573+
574+
if (matterRmNodeIdMap.containsValue(matterDeviceId)) {
575+
for (Map.Entry<String, String> matterDevice : matterRmNodeIdMap.entrySet()) {
576+
if (matterDeviceId.equals(matterDevice.getValue())) {
577+
String rmNodeId = matterDevice.getKey();
578+
if (nodeMap.containsKey(rmNodeId)) {
579+
int nodeStatus = nodeMap.get(rmNodeId).getNodeStatus();
580+
if (nodeStatus != AppConstants.NODE_STATUS_MATTER_LOCAL && nodeStatus != AppConstants.NODE_STATUS_LOCAL) {
581+
Log.d(TAG, "Set Node status to remotely controllable for node id : " + rmNodeId);
582+
nodeMap.get(rmNodeId).setNodeStatus(AppConstants.NODE_STATUS_REMOTELY_CONTROLLABLE);
583+
}
584+
}
585+
}
586+
}
587+
}
588+
}
589+
} catch (JSONException e) {
590+
e.printStackTrace();
591+
}
592+
}
593+
}
594+
EventBus.getDefault().post(new UpdateEvent(UpdateEventType.EVENT_DEVICE_STATUS_UPDATE));
595+
}
596+
}
597+
547598
private void initChipControllerForHomeGroup() {
548599

549600
Log.d(TAG, "============================= init ChipController for home group");
@@ -619,12 +670,17 @@ public void fetchDeviceMatterInfo(String matterNodeId, String nodeId) {
619670
}
620671
matterDeviceInfoMap.put(matterNodeId, matterDeviceInfo);
621672
nodeMap.get(nodeId).setOnline(true);
673+
nodeMap.get(nodeId).setNodeStatus(AppConstants.NODE_STATUS_MATTER_LOCAL);
622674
availableMatterDevices.add(matterNodeId);
623675
} else {
624676
matterDeviceInfoMap.remove(matterNodeId);
625677
availableMatterDevices.remove(matterNodeId);
626678
chipClientMap.remove(matterNodeId);
627679
nodeMap.get(nodeId).setOnline(false);
680+
if (!Arrays.asList(AppConstants.NODE_STATUS_REMOTELY_CONTROLLABLE, AppConstants.NODE_STATUS_LOCAL,
681+
AppConstants.NODE_STATUS_ONLINE).contains(nodeMap.get(nodeId).getNodeStatus())) {
682+
nodeMap.get(nodeId).setNodeStatus(AppConstants.NODE_STATUS_OFFLINE);
683+
}
628684
}
629685
} catch (ExecutionException e) {
630686
e.printStackTrace();
@@ -1088,6 +1144,7 @@ public void onSuccess(Bundle data) {
10881144
localNode.setIpAddress(localDevice.getIpAddr());
10891145
localNode.setPort(localDevice.getPort());
10901146
localNode.setOnline(true);
1147+
localNode.setNodeStatus(AppConstants.NODE_STATUS_LOCAL);
10911148
localDeviceMap.put(localNode.getNodeId(), localDevice);
10921149
}
10931150

0 commit comments

Comments
 (0)