diff --git a/lib/infrastructure/devices/esphome/esphome_connector_conjector.dart b/lib/infrastructure/devices/esphome/esphome_connector_conjector.dart index 8b4ebae1..a0cec27d 100644 --- a/lib/infrastructure/devices/esphome/esphome_connector_conjector.dart +++ b/lib/infrastructure/devices/esphome/esphome_connector_conjector.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:collection'; import 'package:cbj_hub/domain/generic_devices/abstract_device/core_failures.dart'; import 'package:cbj_hub/domain/generic_devices/abstract_device/device_entity_abstract.dart'; @@ -17,6 +18,7 @@ class EspHomeConnectorConjector implements AbstractCompanyConnectorConjector { static const List mdnsTypes = ['_esphomelib._tcp']; static Map companyDevices = {}; + static HashSet lastMdnsName = HashSet(); /// Add new devices to [companyDevices] if not exist Future addNewDeviceByMdnsName({ @@ -27,6 +29,15 @@ class EspHomeConnectorConjector implements AbstractCompanyConnectorConjector { }) async { CoreUniqueId? tempCoreUniqueId; + // Python process take so much that the same result can arrive again + // before the device completed the process and got add + // This fixe it + if (lastMdnsName.contains(mDnsName)) { + return; + } + + lastMdnsName.add(mDnsName); + for (final DeviceEntityAbstract device in companyDevices.values) { if (device is EspHomeLightEntity && mDnsName == device.vendorUniqueId.getOrCrash()) { diff --git a/lib/infrastructure/devices/esphome/esphome_helpers.dart b/lib/infrastructure/devices/esphome/esphome_helpers.dart index 7ea680b4..3fdaf6e7 100644 --- a/lib/infrastructure/devices/esphome/esphome_helpers.dart +++ b/lib/infrastructure/devices/esphome/esphome_helpers.dart @@ -1,5 +1,7 @@ import 'package:cbj_hub/domain/generic_devices/abstract_device/device_entity_abstract.dart'; import 'package:cbj_hub/infrastructure/devices/esphome/esphome_python_api/esphome_python_api.dart'; +import 'package:cbj_hub/infrastructure/system_commands/system_commands_manager_d.dart'; +import 'package:cbj_hub/injection.dart'; class EspHomeHelpers { static Future> addDiscoverdEntities({ @@ -7,12 +9,19 @@ class EspHomeHelpers { required String mDnsName, String port = '6053', }) async { - final List deviceEntityList = - await EspHomePythonApi.getAllEntities( + final HelperEspHomeDeviceInfo helperEspHomeDeviceInfo = + HelperEspHomeDeviceInfo( address: address, - mDnsName: mDnsName, port: port, + deviceKey: 'null', + newState: 'null', + mDnsName: mDnsName, + devicePassword: 'null', + getProjectFilesLocation: + await getIt().getProjectFilesLocation(), ); + final List deviceEntityList = + await EspHomePythonApi.getAllEntities(helperEspHomeDeviceInfo); return deviceEntityList; } diff --git a/lib/infrastructure/devices/esphome/esphome_light/esphome_light_entity.dart b/lib/infrastructure/devices/esphome/esphome_light/esphome_light_entity.dart index ca136116..353cf905 100644 --- a/lib/infrastructure/devices/esphome/esphome_light/esphome_light_entity.dart +++ b/lib/infrastructure/devices/esphome/esphome_light/esphome_light_entity.dart @@ -6,7 +6,10 @@ import 'package:cbj_hub/domain/generic_devices/generic_light_device/generic_ligh import 'package:cbj_hub/domain/generic_devices/generic_light_device/generic_light_value_objects.dart'; import 'package:cbj_hub/infrastructure/devices/esphome/esphome_python_api/esphome_python_api.dart'; import 'package:cbj_hub/infrastructure/gen/cbj_hub_server/protoc_as_dart/cbj_hub_server.pbgrpc.dart'; +import 'package:cbj_hub/infrastructure/system_commands/system_commands_manager_d.dart'; +import 'package:cbj_hub/injection.dart'; import 'package:cbj_hub/utils.dart'; +import 'package:compute/compute.dart'; import 'package:dartz/dartz.dart'; class EspHomeLightEntity extends GenericLightDE { @@ -98,13 +101,25 @@ class EspHomeLightEntity extends GenericLightDE { lightSwitchState = GenericLightSwitchState(DeviceActions.on.toString()); try { - logger.v('Turn on ESPHome Light'); - await EspHomePythonApi.turnOnOffLightEntity( + final HelperEspHomeDeviceInfo helperEspHomeDeviceInfo = + HelperEspHomeDeviceInfo( address: lastKnownIp!.getOrCrash(), port: devicePort.getOrCrash(), deviceKey: espHomeKey.getOrCrash(), newState: 'True', + mDnsName: 'null', + devicePassword: 'null', + getProjectFilesLocation: + await getIt().getProjectFilesLocation(), + ); + + logger.v('Turn on ESPHome Light'); + await compute( + EspHomePythonApi.turnOnOffLightEntity, + helperEspHomeDeviceInfo, ); + + await EspHomePythonApi.turnOnOffLightEntity(helperEspHomeDeviceInfo); return right(unit); } catch (e) { return left(const CoreFailure.unexpected()); @@ -116,11 +131,21 @@ class EspHomeLightEntity extends GenericLightDE { lightSwitchState = GenericLightSwitchState(DeviceActions.off.toString()); try { - await EspHomePythonApi.turnOnOffLightEntity( + final HelperEspHomeDeviceInfo helperEspHomeDeviceInfo = + HelperEspHomeDeviceInfo( address: lastKnownIp!.getOrCrash(), port: devicePort.getOrCrash(), deviceKey: espHomeKey.getOrCrash(), newState: 'False', + mDnsName: 'null', + devicePassword: 'null', + getProjectFilesLocation: + await getIt().getProjectFilesLocation(), + ); + + await compute( + EspHomePythonApi.turnOnOffLightEntity, + helperEspHomeDeviceInfo, ); return right(unit); } catch (e) { diff --git a/lib/infrastructure/devices/esphome/esphome_python_api/esphome_python_api.dart b/lib/infrastructure/devices/esphome/esphome_python_api/esphome_python_api.dart index 78a99c41..fa47e985 100644 --- a/lib/infrastructure/devices/esphome/esphome_python_api/esphome_python_api.dart +++ b/lib/infrastructure/devices/esphome/esphome_python_api/esphome_python_api.dart @@ -1,7 +1,5 @@ import 'package:cbj_hub/domain/generic_devices/abstract_device/device_entity_abstract.dart'; import 'package:cbj_hub/infrastructure/devices/esphome/esphome_python_api/esphome_python_json_objects_type.dart'; -import 'package:cbj_hub/infrastructure/system_commands/system_commands_manager_d.dart'; -import 'package:cbj_hub/injection.dart'; import 'package:cbj_hub/utils.dart'; import 'package:python_shell/python_shell.dart'; @@ -17,14 +15,14 @@ class EspHomePythonApi { _shell = PythonShell(PythonShellConfig()); await _shell!.initialize(); + final instance = ShellManager.getInstance("default"); + instance.installRequires(requeiredPythonPackages); return _shell!; } - static Future> getAllEntities({ - required String address, - required String mDnsName, - required String port, - }) async { + static Future> getAllEntities( + HelperEspHomeDeviceInfo helperEspHomeDeviceInfo, + ) async { const String devicePassword = 'MyPassword'; final List devicesList = []; @@ -32,7 +30,6 @@ class EspHomePythonApi { await getShell(); final instance = ShellManager.getInstance("default"); - instance.installRequires(requeiredPythonPackages); String? currentType; @@ -43,9 +40,9 @@ class EspHomePythonApi { EsphomePythonJsonObjectsType.getDeviceAsAbstractIfExist( currentType: currentType!, deviceJson: message, - address: address, - mDnsName: mDnsName, - port: port, + address: helperEspHomeDeviceInfo.address, + mDnsName: helperEspHomeDeviceInfo.mDnsName, + port: helperEspHomeDeviceInfo.port, ); if (convertedDevice != null) { devicesList.add(convertedDevice); @@ -64,11 +61,11 @@ class EspHomePythonApi { ); await instance.runFile( - '${await getIt().getProjectFilesLocation()}/lib/infrastructure/devices/esphome/esphome_python_api/esphome_python_files/get_esphome_entities.py', + '${helperEspHomeDeviceInfo.getProjectFilesLocation}/lib/infrastructure/devices/esphome/esphome_python_api/esphome_python_files/get_esphome_entities.py', listener: shellListener, arguments: [ - address, - port, + helperEspHomeDeviceInfo.address, + helperEspHomeDeviceInfo.port, devicePassword, ], echo: false, @@ -79,18 +76,14 @@ class EspHomePythonApi { return devicesList; } - static Future turnOnOffLightEntity({ - required String address, - required String port, - required String deviceKey, - required String newState, - }) async { + static Future turnOnOffLightEntity( + HelperEspHomeDeviceInfo helperEspHomeDeviceInfo, + ) async { const String devicePassword = 'MyPassword'; await getShell(); final instance = ShellManager.getInstance("default"); - instance.installRequires(requeiredPythonPackages); final ShellListener shellListener = ShellListener( onMessage: (String message) {}, @@ -103,31 +96,27 @@ class EspHomePythonApi { ); await instance.runFile( - '${await getIt().getProjectFilesLocation()}/lib/infrastructure/devices/esphome/esphome_python_api/esphome_python_files/turn_on_off_light_entity_esphome_devices.py', + '${helperEspHomeDeviceInfo.getProjectFilesLocation}/lib/infrastructure/devices/esphome/esphome_python_api/esphome_python_files/turn_on_off_light_entity_esphome_devices.py', listener: shellListener, arguments: [ - address, - port, - devicePassword, - deviceKey, - newState, + helperEspHomeDeviceInfo.address, + helperEspHomeDeviceInfo.port, + helperEspHomeDeviceInfo.devicePassword, + helperEspHomeDeviceInfo.deviceKey, + helperEspHomeDeviceInfo.newState, ], echo: false, ); } - static Future turnOnOffSwitchEntity({ - required String address, - required String port, - required String deviceKey, - required String newState, - }) async { + static Future turnOnOffSwitchEntity( + HelperEspHomeDeviceInfo helperEspHomeDeviceInfo, + ) async { const String devicePassword = 'MyPassword'; await getShell(); final instance = ShellManager.getInstance("default"); - instance.installRequires(requeiredPythonPackages); final ShellListener shellListener = ShellListener( onMessage: (String message) {}, @@ -140,16 +129,36 @@ class EspHomePythonApi { ); await instance.runFile( - '${await getIt().getProjectFilesLocation()}/lib/infrastructure/devices/esphome/esphome_python_api/esphome_python_files/turn_on_off_switch_entity_esphome_devices.py', + '${helperEspHomeDeviceInfo.getProjectFilesLocation}/lib/infrastructure/devices/esphome/esphome_python_api/esphome_python_files/turn_on_off_switch_entity_esphome_devices.py', listener: shellListener, arguments: [ - address, - port, - devicePassword, - deviceKey, - newState, + helperEspHomeDeviceInfo.address, + helperEspHomeDeviceInfo.port, + helperEspHomeDeviceInfo.devicePassword, + helperEspHomeDeviceInfo.deviceKey, + helperEspHomeDeviceInfo.newState, ], echo: false, ); } } + +class HelperEspHomeDeviceInfo { + HelperEspHomeDeviceInfo({ + required this.address, + required this.port, + required this.deviceKey, + required this.newState, + required this.mDnsName, + required this.devicePassword, + required this.getProjectFilesLocation, + }); + + String address; + String port; + String deviceKey; + String newState; + String mDnsName; + String devicePassword; + String getProjectFilesLocation; +} diff --git a/lib/infrastructure/devices/esphome/esphome_switch/esphome_switch_entity.dart b/lib/infrastructure/devices/esphome/esphome_switch/esphome_switch_entity.dart index dc338f81..d9ef4c1a 100644 --- a/lib/infrastructure/devices/esphome/esphome_switch/esphome_switch_entity.dart +++ b/lib/infrastructure/devices/esphome/esphome_switch/esphome_switch_entity.dart @@ -6,7 +6,10 @@ import 'package:cbj_hub/domain/generic_devices/generic_switch_device/generic_swi import 'package:cbj_hub/domain/generic_devices/generic_switch_device/generic_switch_value_objects.dart'; import 'package:cbj_hub/infrastructure/devices/esphome/esphome_python_api/esphome_python_api.dart'; import 'package:cbj_hub/infrastructure/gen/cbj_hub_server/protoc_as_dart/cbj_hub_server.pbgrpc.dart'; +import 'package:cbj_hub/infrastructure/system_commands/system_commands_manager_d.dart'; +import 'package:cbj_hub/injection.dart'; import 'package:cbj_hub/utils.dart'; +import 'package:compute/compute.dart'; import 'package:dartz/dartz.dart'; class EspHomeSwitchEntity extends GenericSwitchDE { @@ -97,11 +100,21 @@ class EspHomeSwitchEntity extends GenericSwitchDE { switchState = GenericSwitchSwitchState(DeviceActions.on.toString()); try { - await EspHomePythonApi.turnOnOffSwitchEntity( + final HelperEspHomeDeviceInfo helperEspHomeDeviceInfo = + HelperEspHomeDeviceInfo( address: lastKnownIp!.getOrCrash(), port: devicePort.getOrCrash(), deviceKey: espHomeKey.getOrCrash(), newState: 'True', + mDnsName: 'null', + devicePassword: 'null', + getProjectFilesLocation: + await getIt().getProjectFilesLocation(), + ); + + await compute( + EspHomePythonApi.turnOnOffSwitchEntity, + helperEspHomeDeviceInfo, ); logger.v('Turn on ESPHome switch'); return right(unit); @@ -115,12 +128,22 @@ class EspHomeSwitchEntity extends GenericSwitchDE { switchState = GenericSwitchSwitchState(DeviceActions.off.toString()); try { - logger.v('Turn off ESPHome device'); - await EspHomePythonApi.turnOnOffSwitchEntity( + final HelperEspHomeDeviceInfo helperEspHomeDeviceInfo = + HelperEspHomeDeviceInfo( address: lastKnownIp!.getOrCrash(), port: devicePort.getOrCrash(), deviceKey: espHomeKey.getOrCrash(), newState: 'False', + mDnsName: 'null', + devicePassword: 'null', + getProjectFilesLocation: + await getIt().getProjectFilesLocation(), + ); + + logger.v('Turn off ESPHome device'); + await compute( + EspHomePythonApi.turnOnOffSwitchEntity, + helperEspHomeDeviceInfo, ); return right(unit); } catch (e) { diff --git a/pubspec.yaml b/pubspec.yaml index b9415747..975f68d3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -12,6 +12,8 @@ dependencies: async: ^2.10.0 # Package to create, convert, alter, and compare colors in a variety of colorspaces. color: ^3.0.0 + # Compute function made available for all non-Flutter Dart programs + compute: ^1.0.2 # Collection of cyclic redundancy check (CRC) routines as Dart converters. crclib: ^3.0.0 # Functional programming thingies, let you use multiple return types