Skip to content

Commit

Permalink
Merge branch 'feature/matter_controller_remote_api_support' into 'mas…
Browse files Browse the repository at this point in the history
…ter'

Added support for controlling matter-only devices remotely via controller.

See merge request app-frameworks/esp-rainmaker-android!82
  • Loading branch information
adwait-esp committed May 22, 2024
2 parents 21753df + 0a06cf6 commit c611098
Show file tree
Hide file tree
Showing 15 changed files with 1,544 additions and 287 deletions.
4 changes: 2 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ android {
applicationId "com.espressif.rainmaker"
minSdkVersion 27
targetSdkVersion 34
versionCode 117
versionName "3.2.4 - ${getGitHash()}"
versionCode 119
versionName "3.3.0 - ${getGitHash()}"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

buildConfigField "String", "GitHash", "\"${getGitHash()}\""
Expand Down
12 changes: 12 additions & 0 deletions app/src/main/java/com/espressif/AppConstants.kt
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ class AppConstants {
const val SERVICE_TYPE_TIME = "esp.service.time"
const val SERVICE_TYPE_LOCAL_CONTROL = "esp.service.local_control"
const val SERVICE_TYPE_SYSTEM = "esp.service.system"
const val SERVICE_TYPE_MATTER_CONTROLLER = "esp.service.matter-controller"

// Param Types
const val PARAM_TYPE_NAME = "esp.param.name"
Expand All @@ -89,6 +90,9 @@ class AppConstants {
const val PARAM_TYPE_REBOOT = "esp.param.reboot"
const val PARAM_TYPE_FACTORY_RESET = "esp.param.factory-reset"
const val PARAM_TYPE_WIFI_RESET = "esp.param.wifi-reset"
const val PARAM_TYPE_MATTER_DEVICES = "esp.param.matter-devices"
const val PARAM_TYPE_MATTER_CTRL_DATA_VERSION =
"esp.param.matter-controller-data-version"

// Param names
const val PARAM_POWER = "Power"
Expand Down Expand Up @@ -345,6 +349,8 @@ class AppConstants {
const val KEY_AUTOMATION = "automation"
const val KEY_LOAD_AUTOMATION_PAGE = "load_automation"
const val KEY_SYSTEM = "System"
const val KEY_MATTER_CONTROLLER = "Matter-Controller"
const val KEY_REACHABLE = "reachable"

const val KEY_OPERATION = "operation"
const val KEY_OPERATION_ADD = "add"
Expand Down Expand Up @@ -461,6 +467,12 @@ class AppConstants {
const val PRIVILEGE_ADMIN = 5
const val PRIVILEGE_OPERATE = 3

const val NODE_STATUS_OFFLINE = 1;
const val NODE_STATUS_ONLINE = 2;
const val NODE_STATUS_LOCAL = 3;
const val NODE_STATUS_MATTER_LOCAL = 4;
const val NODE_STATUS_REMOTELY_CONTROLLABLE = 5;

enum class UpdateEventType {
EVENT_DEVICE_ADDED,
EVENT_DEVICE_REMOVED,
Expand Down
61 changes: 61 additions & 0 deletions app/src/main/java/com/espressif/ESPControllerAPIKeys.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Copyright 2024 Espressif Systems (Shanghai) PTE LTD
//
// 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.

package com.espressif

class ESPControllerAPIKeys {

companion object {

const val KEY_MATTER_CONTROLLER = "matter-controller"
const val KEY_MATTER_CONTROLLER_DATA_VERSION = "matter-controller-data-version"
const val KEY_MATTER_CONTROLLER_DATA = "matter-controller-data"
const val KEY_DATA = "data"
const val KEY_ENABLED = "enabled"
const val KEY_REACHABLE = "reachable"
const val KEY_MATTER_NODES = "matter-nodes"
const val KEY_MATTER_NODE_ID = "matter-node-id"
const val KEY_ENDPOINTS = "endpoints"
const val KEY_ENDPOINT_ID = "endpoint-id"
const val KEY_CLUSTERS = "clusters"
const val KEY_CLUSTER_ID = "cluster-id"
const val KEY_COMMANDS = "commands"
const val KEY_COMMAND_ID = "command-id"

const val ENDPOINT_ID_1 = "0x1"

const val CLUSTER_ID_ON_OFF = "0x6"
const val CLUSTER_ID_LEVEL_CONTROL = "0x8"
const val CLUSTER_ID_COLOR_CONTROL = "0x300"
const val CLUSTER_ID_THERMOSTAT = "0x201"
const val CLUSTER_ID_TEMPERATURE_MEASUREMENT = "0x402"

const val COMMAND_ID_OFF = "0x0"
const val COMMAND_ID_ON = "0x1"
const val COMMAND_ID_TOGGLE = "0x2"
const val COMMAND_ID_MOVE_TO_LEVEL_WITH_ON_OFF = "0x0"
const val COMMAND_ID_MOVE_TO_SATURATION = "0x3"
const val COMMAND_ID_MOVE_TO_HUE = "0x0"

const val ATTRIBUTE_ID_ON_OFF = "0x0"
const val ATTRIBUTE_ID_BRIGHTNESS_LEVEL = "0x0"
const val ATTRIBUTE_ID_CURRENT_HUE = "0x0"
const val ATTRIBUTE_ID_CURRENT_SATURATION = "0x1"
const val ATTRIBUTE_ID_LOCAL_TEMPERATURE = "0x0"
const val ATTRIBUTE_ID_SYSTEM_MODE = "0x1c"
const val ATTRIBUTE_ID_OCCUPIED_COOLING_SETPOINT = "0x11"
const val ATTRIBUTE_ID_OCCUPIED_HEATING_SETPOINT = "0x12"
const val ATTRIBUTE_ID_MEASURED_TEMPERATURE = "0x0"
}
}
59 changes: 58 additions & 1 deletion app/src/main/java/com/espressif/EspApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.HashMap;
import java.util.Iterator;
Expand Down Expand Up @@ -116,6 +117,7 @@ public class EspApplication extends Application {
public HashMap<String, ChipClient> chipClientMap;
public HashMap<String, List<DeviceMatterInfo>> matterDeviceInfoMap;
public ArrayList<String> availableMatterDevices;
public HashMap<String, HashMap<String, String>> controllerDevices;
public EspOtaUpdate otaUpdateInfo;

private SharedPreferences appPreferences;
Expand Down Expand Up @@ -149,6 +151,7 @@ public void onCreate() {
chipClientMap = new HashMap<>();
matterDeviceInfoMap = new HashMap<>();
availableMatterDevices = new ArrayList<>();
controllerDevices = new HashMap<>();

appPreferences = getSharedPreferences(AppConstants.ESP_PREFERENCES, Context.MODE_PRIVATE);
BASE_URL = appPreferences.getString(AppConstants.KEY_BASE_URL, BuildConfig.BASE_URL);
Expand Down Expand Up @@ -215,7 +218,11 @@ public void changeAppState(AppState newState, Bundle extras) {
if (!chipClientMap.containsKey(matterNodeId)) {
clientHelper.initChipClientInBackground(matterNodeId);
} else {
clientHelper.getCurrentValues(nodeId, matterNodeId, nodeMap.get(nodeId));
try {
clientHelper.getCurrentValues(nodeId, matterNodeId, nodeMap.get(nodeId));
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
break;
Expand Down Expand Up @@ -529,6 +536,7 @@ public void onSuccess(Bundle data) {
}
}
}
setRemoteDeviceStatus();
changeAppState(AppState.GET_DATA_SUCCESS, null);
}

Expand All @@ -544,6 +552,49 @@ public void onNetworkFailure(Exception exception) {
});
}

private void setRemoteDeviceStatus() {

for (Map.Entry<String, HashMap<String, String>> entry : controllerDevices.entrySet()) {

String controllerNodeId = entry.getKey();
HashMap<String, String> matterOnlyDevices = entry.getValue();

for (Map.Entry<String, String> controllerDevice : matterOnlyDevices.entrySet()) {
String matterDeviceId = controllerDevice.getKey();
String jsonStr = controllerDevice.getValue();

if (jsonStr != null) {
try {
JSONObject deviceJson = new JSONObject(jsonStr);
boolean enabled = deviceJson.optBoolean(AppConstants.KEY_ENABLED);
boolean reachable = deviceJson.optBoolean(AppConstants.KEY_REACHABLE);

if (enabled && reachable) {

if (matterRmNodeIdMap.containsValue(matterDeviceId)) {
for (Map.Entry<String, String> matterDevice : matterRmNodeIdMap.entrySet()) {
if (matterDeviceId.equals(matterDevice.getValue())) {
String rmNodeId = matterDevice.getKey();
if (nodeMap.containsKey(rmNodeId)) {
int nodeStatus = nodeMap.get(rmNodeId).getNodeStatus();
if (nodeStatus != AppConstants.NODE_STATUS_MATTER_LOCAL && nodeStatus != AppConstants.NODE_STATUS_LOCAL) {
Log.d(TAG, "Set Node status to remotely controllable for node id : " + rmNodeId);
nodeMap.get(rmNodeId).setNodeStatus(AppConstants.NODE_STATUS_REMOTELY_CONTROLLABLE);
}
}
}
}
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
EventBus.getDefault().post(new UpdateEvent(UpdateEventType.EVENT_DEVICE_STATUS_UPDATE));
}
}

private void initChipControllerForHomeGroup() {

Log.d(TAG, "============================= init ChipController for home group");
Expand Down Expand Up @@ -619,12 +670,17 @@ public void fetchDeviceMatterInfo(String matterNodeId, String nodeId) {
}
matterDeviceInfoMap.put(matterNodeId, matterDeviceInfo);
nodeMap.get(nodeId).setOnline(true);
nodeMap.get(nodeId).setNodeStatus(AppConstants.NODE_STATUS_MATTER_LOCAL);
availableMatterDevices.add(matterNodeId);
} else {
matterDeviceInfoMap.remove(matterNodeId);
availableMatterDevices.remove(matterNodeId);
chipClientMap.remove(matterNodeId);
nodeMap.get(nodeId).setOnline(false);
if (!Arrays.asList(AppConstants.NODE_STATUS_REMOTELY_CONTROLLABLE, AppConstants.NODE_STATUS_LOCAL,
AppConstants.NODE_STATUS_ONLINE).contains(nodeMap.get(nodeId).getNodeStatus())) {
nodeMap.get(nodeId).setNodeStatus(AppConstants.NODE_STATUS_OFFLINE);
}
}
} catch (ExecutionException e) {
e.printStackTrace();
Expand Down Expand Up @@ -1088,6 +1144,7 @@ public void onSuccess(Bundle data) {
localNode.setIpAddress(localDevice.getIpAddr());
localNode.setPort(localDevice.getPort());
localNode.setOnline(true);
localNode.setNodeStatus(AppConstants.NODE_STATUS_LOCAL);
localDeviceMap.put(localNode.getNodeId(), localDevice);
}

Expand Down
Loading

0 comments on commit c611098

Please sign in to comment.