Skip to content

Commit

Permalink
Merge branch 'bugfix/matter_node_connectivity' into 'master'
Browse files Browse the repository at this point in the history
Improved matter node connectivity handling

See merge request app-frameworks/esp-rainmaker-android!81
  • Loading branch information
adwait-esp committed Mar 27, 2024
2 parents 9cd4e48 + 9ee2e54 commit 036881a
Show file tree
Hide file tree
Showing 6 changed files with 162 additions and 35 deletions.
4 changes: 3 additions & 1 deletion app/src/main/java/com/espressif/AppConstants.kt
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,7 @@ class AppConstants {
// Node types
const val NODE_TYPE_PURE_MATTER = "pure_matter"
const val NODE_TYPE_RM_MATTER = "rainmaker_matter"
const val NODE_TYPE_RM = "rainmaker"

// Endpoints, Cluster Id, Attribute Ids
const val ENDPOINT_0 = 0
Expand Down Expand Up @@ -450,7 +451,8 @@ class AppConstants {
EVENT_DEVICE_STATUS_UPDATE,
EVENT_STATE_CHANGE_UPDATE,
EVENT_LOCAL_DEVICE_UPDATE,
EVENT_CTRL_CONFIG_DONE
EVENT_CTRL_CONFIG_DONE,
EVENT_MATTER_DEVICE_CONNECTIVITY
}
}
}
12 changes: 5 additions & 7 deletions app/src/main/java/com/espressif/EspApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import com.espressif.local_control.LocalControlApiManager;
import com.espressif.local_control.mDNSManager;
import com.espressif.matter.ChipClient;
import com.espressif.matter.ChipClientHelper;
import com.espressif.matter.ClustersHelper;
import com.espressif.matter.DeviceMatterInfo;
import com.espressif.matter.LevelControlClusterHelper;
Expand Down Expand Up @@ -208,7 +209,8 @@ public void changeAppState(AppState newState, Bundle extras) {
startLocalDeviceDiscovery();
for (Map.Entry<String, String> entry : matterRmNodeIdMap.entrySet()) {
String matterNodeId = entry.getValue();
initChipController(matterNodeId);
ChipClientHelper clientHelper = new ChipClientHelper(this);
clientHelper.initChipClientInBackground(matterNodeId);
}
break;
}
Expand Down Expand Up @@ -666,15 +668,11 @@ public void fetchDeviceMatterInfo(String matterNodeId, String nodeId) {
matterDeviceInfoMap.put(matterNodeId, matterDeviceInfo);
nodeMap.get(nodeId).setOnline(true);
availableMatterDevices.add(matterNodeId);
EventBus.getDefault().post(new UpdateEvent(UpdateEventType.EVENT_DEVICE_ONLINE));
} else {
matterDeviceInfoMap.remove(matterNodeId);
availableMatterDevices.remove(matterNodeId);
chipClientMap.remove(matterNodeId);
if (nodeMap.containsKey(nodeId)) {
nodeMap.get(nodeId).setOnline(false);
}
EventBus.getDefault().post(new UpdateEvent(UpdateEventType.EVENT_DEVICE_OFFLINE));
nodeMap.get(nodeId).setOnline(false);
}
} catch (ExecutionException e) {
e.printStackTrace();
Expand All @@ -683,7 +681,7 @@ public void fetchDeviceMatterInfo(String matterNodeId, String nodeId) {
}
}

private void addParamsForMatterOnlyDevice(String nodeId, String matterNodeId, EspNode node) {
public void addParamsForMatterOnlyDevice(String nodeId, String matterNodeId, EspNode node) {

BigInteger id = new BigInteger(matterNodeId, 16);
long deviceId = id.longValue();
Expand Down
102 changes: 102 additions & 0 deletions app/src/main/java/com/espressif/matter/ChipClientHelper.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// 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.matter

import android.os.Bundle
import android.text.TextUtils
import android.util.Log
import com.espressif.AppConstants
import com.espressif.AppConstants.Companion.UpdateEventType
import com.espressif.EspApplication
import com.espressif.ui.models.EspNode
import com.espressif.ui.models.UpdateEvent
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.future.future
import org.greenrobot.eventbus.EventBus

class ChipClientHelper constructor(private val espApp: EspApplication) {

companion object {
const val TAG = "ChipClientHelper"
}

suspend fun initChipClient(matterNodeId: String) {

Log.d(TAG, "Init ChipController for matter node id : $matterNodeId")
if (TextUtils.isEmpty(matterNodeId)) {
Log.e(
TAG,
"======= Init ChipController will not be done. Matter node id is not available"
)
EventBus.getDefault()
.post(UpdateEvent(UpdateEventType.EVENT_MATTER_DEVICE_CONNECTIVITY))
return;
}

for ((_, g) in espApp.groupMap.entries) {
if (g.isMatter) {
val nodeDetails = g.nodeDetails
if (nodeDetails != null) {
for ((nodeId, mNodeId) in nodeDetails.entries) {
var fabricId = ""
var ipk = ""
var rootCa = ""
if (matterNodeId != mNodeId) {
continue
}
Log.d(
TAG,
"Node detail, node id : $nodeId and matter node id : $matterNodeId"
)
if (g.fabricDetails != null) {
fabricId = g.fabricDetails.fabricId
rootCa = g.fabricDetails.rootCa
ipk = g.fabricDetails.ipk
if (!espApp.chipClientMap.containsKey(matterNodeId)) {
if (!TextUtils.isEmpty(fabricId) && !TextUtils.isEmpty(rootCa)
&& !TextUtils.isEmpty(ipk) && !TextUtils.isEmpty(matterNodeId) && !TextUtils.isEmpty(
matterNodeId
)
) {
val chipClient = ChipClient(
espApp, g.groupId, fabricId, rootCa, ipk
)
espApp.chipClientMap.put(matterNodeId, chipClient)
}
}
espApp.fetchDeviceMatterInfo(matterNodeId, nodeId)
val node: EspNode? = espApp.nodeMap.get(nodeId)
if (node != null) {
val nodeType = node.newNodeType
if (!TextUtils.isEmpty(nodeType) && nodeType == AppConstants.NODE_TYPE_PURE_MATTER) {
espApp.addParamsForMatterOnlyDevice(nodeId, matterNodeId, node)
}
}
Log.d(TAG, "Init and fetch cluster info done for the device")
}
}
}
}
}
var updateEvent = UpdateEvent(UpdateEventType.EVENT_MATTER_DEVICE_CONNECTIVITY)
var data = Bundle()
data.putString(AppConstants.KEY_MATTER_NODE_ID, matterNodeId)
updateEvent.data = data
EventBus.getDefault().post(updateEvent)
}

fun initChipClientInBackground(matterNodeId: String) =
GlobalScope.future { initChipClient(matterNodeId) }
}
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,8 @@ public class EspDeviceActivity extends AppCompatActivity {
private boolean isUpdateView = true;
private long lastUpdateRequestTime = 0;

private boolean isMatterOnly = false, isControllerClusterAvailable = false, isTbrClusterAvailable = false;
private String matterNodeId;
private boolean isControllerClusterAvailable = false, isTbrClusterAvailable = false;
private String nodeType, matterNodeId;

@Override
protected void onCreate(Bundle savedInstanceState) {
Expand All @@ -123,23 +123,27 @@ protected void onCreate(Bundle savedInstanceState) {
finish();
} else {
nodeId = device.getNodeId();
Log.e(TAG, "NODE ID : " + nodeId);
Log.d(TAG, "NODE ID : " + nodeId);

isNodeOnline = espApp.nodeMap.get(nodeId).isOnline();
String nodeType = espApp.nodeMap.get(nodeId).getNewNodeType();
nodeType = espApp.nodeMap.get(nodeId).getNewNodeType();
timeStampOfStatus = espApp.nodeMap.get(nodeId).getTimeStampOfStatus();
snackbar = Snackbar.make(findViewById(R.id.params_parent_layout), R.string.msg_no_internet, Snackbar.LENGTH_INDEFINITE);

if (!TextUtils.isEmpty(nodeType)) {
if (nodeType.equals(AppConstants.NODE_TYPE_PURE_MATTER)) {
isMatterOnly = true;
Log.e(TAG, "Pure matter device");
}
if (TextUtils.isEmpty(nodeType)) {
nodeType = AppConstants.NODE_TYPE_RM;
}

if (espApp.matterRmNodeIdMap.containsKey(nodeId)) {
matterNodeId = espApp.matterRmNodeIdMap.get(nodeId);
if (nodeType.equals(AppConstants.NODE_TYPE_PURE_MATTER)
|| nodeType.equals(AppConstants.NODE_TYPE_RM_MATTER)) {

if (matterNodeId != null && espApp.availableMatterDevices.contains(matterNodeId)
if (espApp.matterRmNodeIdMap.containsKey(nodeId)) {
matterNodeId = espApp.matterRmNodeIdMap.get(nodeId);
}

if (!TextUtils.isEmpty(matterNodeId) && espApp.availableMatterDevices.contains(matterNodeId)
&& espApp.matterDeviceInfoMap.containsKey(matterNodeId)) {

List<DeviceMatterInfo> deviceMatterInfo = espApp.matterDeviceInfoMap.get(matterNodeId);

if (deviceMatterInfo != null && !deviceMatterInfo.isEmpty()) {
Expand All @@ -157,11 +161,12 @@ protected void onCreate(Bundle savedInstanceState) {
}
}
}
} else {
Log.e(TAG, "Matter device info not available");
}
} else {
Log.d(TAG, "RainMaker device type");
}

timeStampOfStatus = espApp.nodeMap.get(nodeId).getTimeStampOfStatus();
snackbar = Snackbar.make(findViewById(R.id.params_parent_layout), R.string.msg_no_internet, Snackbar.LENGTH_INDEFINITE);
setParamList(device.getParams());
initViews();
updateUi();
Expand Down Expand Up @@ -245,6 +250,10 @@ public void onEvent(UpdateEvent event) {
updateUi();
}
break;

case EVENT_MATTER_DEVICE_CONNECTIVITY:
updateUi();
break;
}
}

Expand All @@ -258,10 +267,6 @@ public boolean isNodeOnline() {
return isNodeOnline;
}

public boolean isMatterOnly() {
return isMatterOnly;
}

public void setIsUpdateView(boolean isUpdateView) {
this.isUpdateView = isUpdateView;
}
Expand All @@ -271,7 +276,7 @@ public void setLastUpdateRequestTime(long lastUpdateRequestTime) {
}

public void startUpdateValueTask() {
if (isMatterOnly) {
if (!TextUtils.isEmpty(nodeType) && nodeType.equals(AppConstants.NODE_TYPE_PURE_MATTER)) {
return;
}
shouldGetParams = true;
Expand Down Expand Up @@ -625,10 +630,6 @@ private void updateUi() {

ArrayList<Device> devices = espApp.nodeMap.get(nodeId).getDevices();
isNodeOnline = espApp.nodeMap.get(nodeId).isOnline();
String nodeType = espApp.nodeMap.get(nodeId).getNewNodeType();
if (!TextUtils.isEmpty(nodeType) && nodeType.equals(AppConstants.NODE_TYPE_PURE_MATTER)) {
isMatterOnly = true;
}
timeStampOfStatus = espApp.nodeMap.get(nodeId).getTimeStampOfStatus();

for (int i = 0; i < devices.size(); i++) {
Expand All @@ -645,6 +646,11 @@ private void updateUi() {
return;
}

boolean isMatterOnly = false;
if (!TextUtils.isEmpty(nodeType) && nodeType.equals(AppConstants.NODE_TYPE_PURE_MATTER)) {
isMatterOnly = true;
}

if (!deviceFound && !isMatterOnly) {
Log.e(TAG, "Device does not exist in node list.");
finish();
Expand Down Expand Up @@ -673,6 +679,12 @@ private void updateUi() {
}
tvNodeStatus.setText(R.string.local_device_text);

} else if (!TextUtils.isEmpty(matterNodeId) && espApp.availableMatterDevices.contains(matterNodeId)
&& espApp.matterDeviceInfoMap.containsKey(matterNodeId)) {

rlNodeStatus.setVisibility(View.VISIBLE);
tvNodeStatus.setText(R.string.status_local);

} else {
ivSecureLocal.setVisibility(View.GONE);
String offlineText = getString(R.string.status_offline);
Expand Down Expand Up @@ -707,6 +719,15 @@ private void updateUi() {

} else {

if (!TextUtils.isEmpty(matterNodeId) && espApp.availableMatterDevices.contains(matterNodeId)
&& espApp.matterDeviceInfoMap.containsKey(matterNodeId)) {

rlNodeStatus.setVisibility(View.VISIBLE);
tvNodeStatus.setText(R.string.status_local);
} else {
rlNodeStatus.setVisibility(View.INVISIBLE);
}

if (espApp.localDeviceMap.containsKey(nodeId)) {

rlNodeStatus.setVisibility(View.VISIBLE);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,7 @@ public void onEvent(UpdateEvent event) {
break;

case EVENT_LOCAL_DEVICE_UPDATE:
case EVENT_MATTER_DEVICE_CONNECTIVITY:
updateUi();
break;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,10 @@ public void onBindViewHolder(@NonNull final DeviceViewHolder deviceVh, final int
matterNodeId = espApp.matterRmNodeIdMap.get(nodeId);
}

if (!TextUtils.isEmpty(matterNodeId) && espApp.chipClientMap.containsKey(matterNodeId)) {
if (!TextUtils.isEmpty(matterNodeId) && espApp.availableMatterDevices.contains(matterNodeId)) {
isMatterDeviceOnline = true;
}

// set the data in items
if (TextUtils.isEmpty(deviceName)) {
deviceName = device.getDeviceName();
Expand Down Expand Up @@ -370,7 +370,7 @@ public void onNetworkFailure(Exception exception) {
deviceVh.tvStringValue.setVisibility(View.GONE);
}

if (node != null && !node.isOnline()) {
if (node != null && !node.isOnline() && !isMatterDeviceOnline) {

deviceVh.itemView.setAlpha(0.8f);
deviceVh.ivDeviceStatus.setImageResource(R.drawable.ic_output_disable);
Expand Down Expand Up @@ -427,11 +427,14 @@ public void onNetworkFailure(Exception exception) {
}

if (!TextUtils.isEmpty(matterNodeId) && espApp.availableMatterDevices.contains(matterNodeId)) {

deviceVh.llOffline.setVisibility(View.VISIBLE);
deviceVh.ivOffline.setVisibility(View.GONE);
deviceVh.tvOffline.setText(R.string.status_local);
deviceVh.tvOffline.setTextColor(context.getColor(R.color.colorPrimaryDark));

} else if (espApp.localDeviceMap.containsKey(nodeId)) {

deviceVh.llOffline.setVisibility(View.VISIBLE);

EspLocalDevice localDevice = espApp.localDeviceMap.get(nodeId);
Expand Down

0 comments on commit 036881a

Please sign in to comment.