Skip to content
This repository was archived by the owner on Mar 9, 2025. It is now read-only.

Commit

Permalink
Merge pull request #334 from guyluz11/Add-Matter-support-#57-
Browse files Browse the repository at this point in the history
Add matter support #57
  • Loading branch information
guyluz11 authored Feb 17, 2025
2 parents 7e75362 + 81beac1 commit 6173785
Show file tree
Hide file tree
Showing 14 changed files with 424 additions and 51 deletions.
3 changes: 3 additions & 0 deletions .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions bin/cbj_hub.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ import 'dart:io';
import 'package:cbj_hub/application/boot_up.dart';
import 'package:cbj_hub/infrastructure/core/initialize_integrations_controller.dart';
import 'package:cbj_hub/infrastructure/core/injection.dart';
import 'package:cbj_hub/infrastructure/mqtt_server_repository.dart';
import 'package:cbj_integrations_controller/integrations_controller.dart';

Future main(List<String> arguments) async {
// MqttServerRepository();
await MqttServerRepository().asyncConstructor();
// CbjWebServerRepository();
// NodeRedRepository();
NodeRedRepository();
SharedVariables()
.asyncConstructor(arguments.firstOrNull ?? Directory.current.path);
// arguments[0] is the location of the project
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Future initializeIntegrationsController({
}

// Setting device model and checking if configuration for this model exist
setInstanceForDartNative();
await DevicePinListManager().setPhysicalDeviceType();

Hive.init(await dbPath());
Expand Down
3 changes: 1 addition & 2 deletions lib/infrastructure/core/injection.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import 'package:cbj_hub/infrastructure/core/injection.config.dart';
import 'package:cbj_hub/utils.dart';
import 'package:get_it/get_it.dart';
import 'package:injectable/injectable.dart';
Expand All @@ -12,7 +11,7 @@ late String currentEnv;
Future configureInjection(String environment) async {
currentEnv = environment;
logger.i('Current CyBear Jinni Hub environment name: $currentEnv');
getItCbj.init(environment: environment);
// getItCbj.init(environment: environment);
}

abstract class Env {
Expand Down
31 changes: 31 additions & 0 deletions lib/infrastructure/devices/matter/matter_connector_conjecture.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import 'dart:async';
import 'dart:collection';

import 'package:cbj_hub/infrastructure/devices/matter/matter_helpers.dart';
import 'package:cbj_integrations_controller/integrations_controller.dart';

class MatterConnectorConjecture extends VendorConnectorConjectureService {
factory MatterConnectorConjecture() {
return _instance;
}

MatterConnectorConjecture._singletonContractor()
: super(
VendorsAndServices.matter,
displayName: 'Matter',
imageUrl:
'https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Ftse1.mm.bing.net%2Fth%3Fid%3DOIP.5oTC_gXhq0Tm5U-jFh8MQAHaFj%26pid%3DApi&f=1&ipt=3784aeff30dcaabb602b299e96c2a280e4bfdd0d309fcc3d54d006c04743cdb9&ipo=images',
uniqeMdnsList: ['_matter._tcp.local', '_matterc._udp.local'],
uniqueIdentifierNameInMdns: ['matter'],
);

static final MatterConnectorConjecture _instance =
MatterConnectorConjecture._singletonContractor();

@override
Future<HashMap<String, DeviceEntityBase>> newEntityToVendorDevice(
DeviceEntityBase entity, {
bool fromDb = false,
}) =>
MatterHelpers.addDiscoveredDevice(entity);
}
10 changes: 10 additions & 0 deletions lib/infrastructure/devices/matter/matter_device_validators.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import 'package:cbj_integrations_controller/integrations_controller.dart';
import 'package:dartz/dartz.dart';

Either<CoreFailure<String>, String> validateMatterIdNotEmpty(String input) {
return right(input);
}

Either<CoreFailure<String>, String> validateMatterPortNotEmpty(String input) {
return right(input);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import 'dart:async';

import 'package:cbj_integrations_controller/integrations_controller.dart';
import 'package:dartz/dartz.dart';

class MatterLightEntity extends GenericDimmableLightDE {
MatterLightEntity({
required super.uniqueId,
required super.entityUniqueId,
required super.cbjEntityName,
required super.entityOriginalName,
required super.deviceOriginalName,
required super.deviceVendor,
required super.deviceNetworkLastUpdate,
required super.stateMassage,
required super.senderDeviceOs,
required super.senderDeviceModel,
required super.senderId,
required super.compUuid,
required super.entityStateGRPC,
required super.powerConsumption,
required super.deviceUniqueId,
required super.devicePort,
required super.deviceLastKnownIp,
required super.deviceHostName,
required super.deviceMdns,
required super.srvResourceRecord,
required super.srvTarget,
required super.ptrResourceRecord,
required super.mdnsServiceType,
required super.devicesMacAddress,
required super.entityKey,
required super.requestTimeStamp,
required super.lastResponseFromDeviceTimeStamp,
required super.entitiyCbjUniqueId,
required super.lightSwitchState,
required super.lightBrightness,
}) : super(
cbjDeviceVendor: CbjDeviceVendor(VendorsAndServices.matter),
);

factory MatterLightEntity.fromGeneric(GenericDimmableLightDE entity) {
return MatterLightEntity(
uniqueId: entity.uniqueId,
entityUniqueId: entity.entityUniqueId,
cbjEntityName: entity.cbjEntityName,
entityOriginalName: entity.entityOriginalName,
deviceOriginalName: entity.deviceOriginalName,
deviceVendor: entity.deviceVendor,
deviceNetworkLastUpdate: entity.deviceNetworkLastUpdate,
stateMassage: entity.stateMassage,
senderDeviceOs: entity.senderDeviceOs,
senderDeviceModel: entity.senderDeviceModel,
senderId: entity.senderId,
compUuid: entity.compUuid,
entityStateGRPC: entity.entityStateGRPC,
powerConsumption: entity.powerConsumption,
deviceUniqueId: entity.deviceUniqueId,
devicePort: entity.devicePort,
deviceLastKnownIp: entity.deviceLastKnownIp,
deviceHostName: entity.deviceHostName,
deviceMdns: entity.deviceMdns,
srvResourceRecord: entity.srvResourceRecord,
srvTarget: entity.srvTarget,
ptrResourceRecord: entity.ptrResourceRecord,
mdnsServiceType: entity.mdnsServiceType,
devicesMacAddress: entity.devicesMacAddress,
entityKey: entity.entityKey,
requestTimeStamp: entity.requestTimeStamp,
lastResponseFromDeviceTimeStamp: entity.lastResponseFromDeviceTimeStamp,
lightSwitchState: entity.lightSwitchState,
entitiyCbjUniqueId: entity.entitiyCbjUniqueId,
lightBrightness: entity.lightBrightness,
);
}

@override
Future<Either<CoreFailure, Unit>> turnOnLight() async {
// lightSwitchState =
// GenericDimmableLightSwitchState(EntityActions.on.toString());
// try {
// final String nodeRedApiBaseTopic =
// IMqttServerRepository.instance.getNodeRedApiBaseTopic();
//
// final String nodeRedDevicesTopic =
// IMqttServerRepository.instance.getNodeRedDevicesTopicTypeName();
// final String topic =
// '$nodeRedApiBaseTopic/$nodeRedDevicesTopic/${entityKey.getOrCrash()}/${EspHomeNodeRedApi.deviceStateProperty}/${EspHomeNodeRedApi.inputDeviceProperty}';
//
// IMqttServerRepository.instance
// .publishMessage(topic, """{"state":true}""");
// } catch (e) {
// return left(const CoreFailure.unexpected());
// }
return right(unit);
}

@override
Future<Either<CoreFailure, Unit>> turnOffLight() async {
try {
// final setStateBodyResponse = NodeRedRepository().
//
// if (setStateBodyResponse == null) {
// throw 'setStateBodyResponse is null';
// }

return right(unit);
} catch (e) {
// As we are using the fast = true the response is always
// MatterHttpException Error
return right(unit);
// return left(const CoreFailure.unexpected());
}
}

@override
Future<Either<CoreFailure, Unit>> setBrightness(int value) async {
try {
// final setStateBodyResponse = NodeRedRepository().
//
// if (setStateBodyResponse == null) {
// throw 'setStateBodyResponse is null';
// }

return right(unit);
} catch (e) {
// As we are using the fast = true the response is always
// MatterHttpException Error
return right(unit);
// return left(const CoreFailure.unexpected());
}
}
}
62 changes: 62 additions & 0 deletions lib/infrastructure/devices/matter/matter_helpers.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import 'dart:collection';

import 'package:cbj_hub/infrastructure/devices/matter/matter_entities/matter_light_entity.dart';
import 'package:cbj_integrations_controller/integrations_controller.dart';

class MatterHelpers {
static Future<HashMap<String, DeviceEntityBase>> addDiscoveredDevice(
DeviceEntityBase entity,
) async {
final String entityCbjUniqueId = entity.devicesMacAddress.getOrCrash() ??
entity.deviceMdns.getOrCrash()!;
String name;
final String? deviceMdns = entity.deviceMdns.getOrCrash();
final String? srvTarget = entity.srvTarget.getOrCrash();
if (deviceMdns != null && deviceMdns.contains('-')) {
name = deviceMdns.split('-').first;
} else if (srvTarget != null) {
name = srvTarget;
} else {
name = entity.cbjEntityName.getOrCrash() ?? '';
}

final MatterLightEntity matterDE = MatterLightEntity(
uniqueId: entity.uniqueId,
entityUniqueId: EntityUniqueId(deviceMdns),
cbjEntityName: CbjEntityName(value: name),
entityOriginalName: entity.entityOriginalName,
deviceOriginalName: entity.deviceOriginalName,
entityStateGRPC: EntityState(EntityStateGRPC.ack),
senderDeviceOs: entity.senderDeviceOs,
deviceVendor: entity.deviceVendor,
deviceNetworkLastUpdate: entity.deviceNetworkLastUpdate,
senderDeviceModel: entity.senderDeviceModel,
senderId: entity.senderId,
compUuid: entity.compUuid,
deviceMdns: entity.deviceMdns,
srvResourceRecord: entity.srvResourceRecord,
srvTarget: entity.srvTarget,
ptrResourceRecord: entity.ptrResourceRecord,
mdnsServiceType: entity.mdnsServiceType,
deviceLastKnownIp: entity.deviceLastKnownIp,
stateMassage: entity.stateMassage,
powerConsumption: entity.powerConsumption,
devicePort: entity.devicePort,
deviceUniqueId: entity.deviceUniqueId,
deviceHostName: entity.deviceHostName,
devicesMacAddress: entity.devicesMacAddress,
entityKey: entity.entityKey,
requestTimeStamp: entity.requestTimeStamp,
lastResponseFromDeviceTimeStamp: entity.lastResponseFromDeviceTimeStamp,
entitiyCbjUniqueId: CoreUniqueId.fromUniqueString(entityCbjUniqueId),
lightSwitchState:
GenericDimmableLightSwitchState(EntityActions.undefined.toString()),
lightBrightness: GenericDimmableLightBrightness('100'),
);

return HashMap()
..addEntries([
MapEntry(entityCbjUniqueId, matterDE),
]);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import 'package:cbj_integrations_controller/integrations_controller.dart';

class NodeRedMatterManagerNode extends NodeRedVisualNodeAbstract {
NodeRedMatterManagerNode({
required this.controller,
required this.deviceName,
required this.cluster,
required this.command,
super.name,
}) : super(
type: 'mattercommand',
);

final String controller;
final String deviceName;
final NodeRedMatterCommandClusterEnum cluster;
final NodeRedMatterCommandCommandEnum command;

@override
String toString() {
return '''
{
"id": "$id",
"type": "$type",
"name": "$name",
"controller": "$controller",
"device": "17174800272800391268-1",
"deviceName": "$deviceName",
"command": "${command.name}",
"cluster": "${cluster.asNumber}",
"data": "{}",
"dataType": "json",
"simpleMode": true,
"wires": ${fixWiresForNodeRed()}
}
''';
}
}

enum NodeRedMatterCommandClusterEnum {
onOff(6),
;

const NodeRedMatterCommandClusterEnum(this.asNumber);
final int asNumber;
}

enum NodeRedMatterCommandCommandEnum {
toggle,
;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import 'package:cbj_integrations_controller/integrations_controller.dart';

class NodeRedMatterControllerNode extends NodeRedNodeAbstract {
NodeRedMatterControllerNode()
: super(
type: 'mattercontroller',
);

@override
String toString() {
return '''
{
"id": "$id",
"type": "$type",
}
''';
}
}
Loading

0 comments on commit 6173785

Please sign in to comment.