├── lib ├── src │ ├── model │ │ ├── thingsboard_error.dart │ │ ├── has_name.dart │ │ ├── id │ │ │ ├── has_id.dart │ │ │ ├── event_id.dart │ │ │ ├── audit_log_id.dart │ │ │ ├── rpc_id.dart │ │ │ ├── edge_event_id.dart │ │ │ ├── edge_id.dart │ │ │ ├── role_id.dart │ │ │ ├── user_id.dart │ │ │ ├── alarm_id.dart │ │ │ ├── asset_id.dart │ │ │ ├── queue_id.dart │ │ │ ├── alarm_comment_id.dart │ │ │ ├── device_id.dart │ │ │ ├── tenant_id.dart │ │ │ ├── customer_id.dart │ │ │ ├── rule_node_id.dart │ │ │ ├── admin_settings_id.dart │ │ │ ├── converter_id.dart │ │ │ ├── dashboard_id.dart │ │ │ ├── rule_chain_id.dart │ │ │ ├── blob_entity_id.dart │ │ │ ├── entity_view_id.dart │ │ │ ├── ota_package_id.dart │ │ │ ├── tb_resource_id.dart │ │ │ ├── widget_type_id.dart │ │ │ ├── entity_group_id.dart │ │ │ ├── integration_id.dart │ │ │ ├── asset_profile_id.dart │ │ │ ├── notification_id.dart │ │ │ ├── api_usage_state_id.dart │ │ │ ├── device_credentials_id.dart │ │ │ ├── device_profile_id.dart │ │ │ ├── tenant_profile_id.dart │ │ │ ├── widgets_bundle_id.dart │ │ │ ├── scheduler_event_id.dart │ │ │ ├── component_descriptor_id.dart │ │ │ ├── group_permission_id.dart │ │ │ ├── notification_rule_id.dart │ │ │ ├── notification_target_id.dart │ │ │ ├── notification_request_id.dart │ │ │ ├── notification_template_id.dart │ │ │ ├── oauth2_client_registration_template_id.dart │ │ │ ├── has_uuid.dart │ │ │ ├── id_based.dart │ │ │ ├── ids.dart │ │ │ └── entity_id.dart │ │ ├── has_additional_info.dart │ │ ├── has_tenant_id.dart │ │ ├── has_entity_type.dart │ │ ├── has_customer_id.dart │ │ ├── tenant_entity.dart │ │ ├── has_owner_id.dart │ │ ├── has_ota_package.dart │ │ ├── constants.dart │ │ ├── has_rule_engine_profile.dart │ │ ├── group_entity.dart │ │ ├── mobile │ │ │ ├── mobile_models.dart │ │ │ ├── mobile_info_query.dart │ │ │ ├── store_info.dart │ │ │ ├── recaptcha_model.dart │ │ │ ├── mobile_version_info.dart │ │ │ ├── mobile_self_registration_params.dart │ │ │ ├── pages_layout.dart │ │ │ ├── version_info.dart │ │ │ ├── basic_mobile_info.dart │ │ │ └── login_mobile_info.dart │ │ ├── mobile_session_models.dart │ │ ├── authority_enum.dart │ │ ├── entity_models.dart │ │ ├── custom_translation_model.dart │ │ ├── page │ │ │ ├── sort_order.dart │ │ │ ├── page_data.dart │ │ │ └── page_link.dart │ │ ├── login_models.dart │ │ ├── base_data.dart │ │ ├── additional_info_based.dart │ │ ├── rpc_models.dart │ │ ├── entity_type_models.dart │ │ ├── report_models.dart │ │ ├── rule_node_models.dart │ │ ├── exportable_entity.dart │ │ ├── signup_models.dart │ │ ├── model.dart │ │ ├── contact_based_model.dart │ │ ├── widgets_bundle_model.dart │ │ ├── component_descriptor_models.dart │ │ ├── blob_entity_models.dart │ │ ├── version.dart │ │ ├── resource_models.dart │ │ ├── custom_menu_models.dart │ │ ├── customer_models.dart │ │ ├── audit_log_models.dart │ │ ├── widget_models.dart │ │ └── group_permission_models.dart │ ├── storage │ │ ├── storage.dart │ │ ├── _local_file_storage.dart │ │ ├── local_file_storage.dart │ │ ├── in_memory_storage.dart │ │ ├── tb_storage.dart │ │ └── _local_file_storage_io.dart │ ├── error │ │ ├── _thingsboard_error_handler.dart │ │ ├── thingsboard_error.dart │ │ ├── _thingsboard_error_handler_io.dart │ │ └── _thingsboard_error_handler_html.dart │ ├── service │ │ ├── user_permissions_service.dart │ │ ├── rule_engine_service.dart │ │ ├── owner_service.dart │ │ ├── event_service.dart │ │ ├── mobile_service.dart │ │ ├── report_service.dart │ │ ├── service.dart │ │ ├── custom_menu_service.dart │ │ ├── entity_query_service.dart │ │ ├── custom_translation_service.dart │ │ ├── component_descriptor_service.dart │ │ ├── role_service.dart │ │ ├── audit_log_service.dart │ │ ├── queue_service.dart │ │ ├── notifications_service.dart │ │ ├── blob_entity_service.dart │ │ ├── resource_service.dart │ │ ├── self_register_service.dart │ │ ├── integration_service.dart │ │ ├── tenant_service.dart │ │ ├── group_permission_service.dart │ │ ├── signup_service.dart │ │ ├── converter_service.dart │ │ ├── oauth2_service.dart │ │ ├── asset_profile_service.dart │ │ └── tenant_profile_service.dart │ ├── interceptor │ │ └── interceptor_config.dart │ └── http │ │ └── http_utils.dart └── thingsboard_client.dart ├── example ├── example_utils.dart ├── thingsboard_pe_client.dart ├── user_permissions.dart ├── callbacks.dart ├── mfa.dart ├── device_api.dart ├── ota_package.dart └── entity_group.dart ├── .gitignore ├── analysis_options.yaml ├── test └── thingsboard_client_test.dart ├── pubspec.yaml ├── README.md ├── LICENSE └── CHANGELOG.md /lib/src/model/thingsboard_error.dart: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /lib/src/model/has_name.dart: -------------------------------------------------------------------------------- 1 | abstract mixin class HasName { 2 | String getName(); 3 | } 4 | -------------------------------------------------------------------------------- /lib/src/model/id/has_id.dart: -------------------------------------------------------------------------------- 1 | import 'has_uuid.dart'; 2 | 3 | abstract class HasId { 4 | I? getId(); 5 | } 6 | -------------------------------------------------------------------------------- /lib/src/storage/storage.dart: -------------------------------------------------------------------------------- 1 | export 'tb_storage.dart'; 2 | export 'in_memory_storage.dart'; 3 | export 'local_file_storage.dart'; 4 | -------------------------------------------------------------------------------- /lib/src/model/has_additional_info.dart: -------------------------------------------------------------------------------- 1 | abstract mixin class HasAdditionalInfo { 2 | Map? getAdditionalInfo(); 3 | } 4 | -------------------------------------------------------------------------------- /lib/src/model/has_tenant_id.dart: -------------------------------------------------------------------------------- 1 | import 'id/tenant_id.dart'; 2 | 3 | abstract mixin class HasTenantId { 4 | TenantId? getTenantId(); 5 | } 6 | -------------------------------------------------------------------------------- /lib/src/model/has_entity_type.dart: -------------------------------------------------------------------------------- 1 | import 'entity_type_models.dart'; 2 | 3 | abstract class HasEntityType { 4 | EntityType getEntityType(); 5 | } 6 | -------------------------------------------------------------------------------- /lib/src/model/has_customer_id.dart: -------------------------------------------------------------------------------- 1 | import 'id/customer_id.dart'; 2 | 3 | abstract mixin class HasCustomerId { 4 | CustomerId? getCustomerId(); 5 | } 6 | -------------------------------------------------------------------------------- /lib/src/model/tenant_entity.dart: -------------------------------------------------------------------------------- 1 | import 'has_entity_type.dart'; 2 | import 'has_tenant_id.dart'; 3 | 4 | abstract class TenantEntity implements HasTenantId, HasEntityType {} 5 | -------------------------------------------------------------------------------- /lib/src/model/has_owner_id.dart: -------------------------------------------------------------------------------- 1 | import 'id/entity_id.dart'; 2 | 3 | abstract class HasOwnerId { 4 | EntityId? getOwnerId(); 5 | 6 | void setOwnerId(EntityId entityId); 7 | } 8 | -------------------------------------------------------------------------------- /lib/src/storage/_local_file_storage.dart: -------------------------------------------------------------------------------- 1 | import 'tb_storage.dart'; 2 | 3 | TbStorage createLocalFileStorage(String fileName, [String? path]) => 4 | throw UnsupportedError(''); 5 | -------------------------------------------------------------------------------- /lib/src/storage/local_file_storage.dart: -------------------------------------------------------------------------------- 1 | export '_local_file_storage.dart' 2 | if (dart.library.io) '_local_file_storage_io.dart' 3 | if (dart.library.html) '_local_file_storage.dart'; 4 | -------------------------------------------------------------------------------- /lib/src/error/_thingsboard_error_handler.dart: -------------------------------------------------------------------------------- 1 | import 'thingsboard_error.dart'; 2 | 3 | ThingsboardError toThingsboardError(error, [StackTrace? stackTrace]) => 4 | throw UnsupportedError(''); 5 | -------------------------------------------------------------------------------- /lib/src/model/has_ota_package.dart: -------------------------------------------------------------------------------- 1 | import 'id/ota_package_id.dart'; 2 | 3 | abstract mixin class HasOtaPackage { 4 | OtaPackageId? getFirmwareId(); 5 | 6 | OtaPackageId? getSoftwareId(); 7 | } 8 | -------------------------------------------------------------------------------- /lib/src/model/constants.dart: -------------------------------------------------------------------------------- 1 | class Constants { 2 | static const entryPoints = { 3 | 'login': '/api/auth/login', 4 | 'tokenRefresh': '/api/auth/token', 5 | 'nonTokenBased': '/api/noauth' 6 | }; 7 | } 8 | -------------------------------------------------------------------------------- /lib/src/model/has_rule_engine_profile.dart: -------------------------------------------------------------------------------- 1 | import 'id/rule_chain_id.dart'; 2 | 3 | abstract mixin class HasRuleEngineProfile { 4 | RuleChainId? getDefaultRuleChainId(); 5 | 6 | String? getDefaultQueueName(); 7 | } 8 | -------------------------------------------------------------------------------- /example/example_utils.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | const _chars = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz1234567890'; 4 | Random _rnd = Random(); 5 | 6 | String getRandomString(int length) => String.fromCharCodes(Iterable.generate( 7 | length, (_) => _chars.codeUnitAt(_rnd.nextInt(_chars.length)))); 8 | -------------------------------------------------------------------------------- /lib/src/model/group_entity.dart: -------------------------------------------------------------------------------- 1 | import 'has_customer_id.dart'; 2 | import 'has_owner_id.dart'; 3 | import 'has_name.dart'; 4 | import 'id/has_id.dart'; 5 | import 'id/entity_id.dart'; 6 | import 'tenant_entity.dart'; 7 | 8 | abstract class GroupEntity 9 | implements HasId, HasName, TenantEntity, HasCustomerId, HasOwnerId {} 10 | -------------------------------------------------------------------------------- /lib/thingsboard_client.dart: -------------------------------------------------------------------------------- 1 | /// Dart implementation of ThingsBoard API client. 2 | library thingsboard_pe_client; 3 | 4 | export 'src/thingsboard_client_base.dart'; 5 | export 'src/model/model.dart'; 6 | export 'src/storage/storage.dart'; 7 | export 'src/http/http_utils.dart'; 8 | export 'src/error/thingsboard_error.dart'; 9 | export 'src/service/service.dart'; 10 | -------------------------------------------------------------------------------- /lib/src/model/mobile/mobile_models.dart: -------------------------------------------------------------------------------- 1 | export 'basic_mobile_info.dart'; 2 | export 'login_mobile_info.dart'; 3 | export 'mobile_info_query.dart'; 4 | export 'mobile_self_registration_params.dart'; 5 | export 'mobile_version_info.dart'; 6 | export 'pages_layout.dart'; 7 | export 'recaptcha_model.dart'; 8 | export 'store_info.dart'; 9 | export 'version_info.dart'; 10 | -------------------------------------------------------------------------------- /lib/src/model/id/event_id.dart: -------------------------------------------------------------------------------- 1 | import 'has_uuid.dart'; 2 | 3 | class EventId extends HasUuid { 4 | EventId(String? id) : super(id); 5 | 6 | @override 7 | factory EventId.fromJson(Map json) { 8 | return HasUuid.fromJson(json, (id) => EventId(id)) as EventId; 9 | } 10 | 11 | @override 12 | String toString() { 13 | return 'EventId {id: $id}'; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/src/model/mobile_session_models.dart: -------------------------------------------------------------------------------- 1 | class MobileSessionInfo { 2 | int fcmTokenTimestamp; 3 | 4 | MobileSessionInfo(this.fcmTokenTimestamp); 5 | 6 | MobileSessionInfo.fromJson(Map json) 7 | : fcmTokenTimestamp = json['fcmTokenTimestamp']; 8 | 9 | Map toJson() { 10 | return { 11 | 'fcmTokenTimestamp': fcmTokenTimestamp, 12 | }; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /lib/src/model/id/audit_log_id.dart: -------------------------------------------------------------------------------- 1 | import 'has_uuid.dart'; 2 | 3 | class AuditLogId extends HasUuid { 4 | AuditLogId(String? id) : super(id); 5 | 6 | @override 7 | factory AuditLogId.fromJson(Map json) { 8 | return HasUuid.fromJson(json, (id) => AuditLogId(id)) as AuditLogId; 9 | } 10 | 11 | @override 12 | String toString() { 13 | return 'AuditLogId {id: $id}'; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/src/model/id/rpc_id.dart: -------------------------------------------------------------------------------- 1 | import '../entity_type_models.dart'; 2 | import 'entity_id.dart'; 3 | 4 | class RpcId extends EntityId { 5 | RpcId(String id) : super(EntityType.RPC, id); 6 | 7 | @override 8 | factory RpcId.fromJson(Map json) { 9 | return EntityId.fromJson(json) as RpcId; 10 | } 11 | 12 | @override 13 | String toString() { 14 | return 'RpcId {id: $id}'; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/src/model/id/edge_event_id.dart: -------------------------------------------------------------------------------- 1 | import 'has_uuid.dart'; 2 | 3 | class EdgeEventId extends HasUuid { 4 | EdgeEventId(String? id) : super(id); 5 | 6 | @override 7 | factory EdgeEventId.fromJson(Map json) { 8 | return HasUuid.fromJson(json, (id) => EdgeEventId(id)) as EdgeEventId; 9 | } 10 | 11 | @override 12 | String toString() { 13 | return 'EdgeEventId {id: $id}'; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/src/model/id/edge_id.dart: -------------------------------------------------------------------------------- 1 | import '../entity_type_models.dart'; 2 | import 'entity_id.dart'; 3 | 4 | class EdgeId extends EntityId { 5 | EdgeId(String id) : super(EntityType.EDGE, id); 6 | 7 | @override 8 | factory EdgeId.fromJson(Map json) { 9 | return EntityId.fromJson(json) as EdgeId; 10 | } 11 | 12 | @override 13 | String toString() { 14 | return 'EdgeId {id: $id}'; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/src/model/id/role_id.dart: -------------------------------------------------------------------------------- 1 | import '../entity_type_models.dart'; 2 | import 'entity_id.dart'; 3 | 4 | class RoleId extends EntityId { 5 | RoleId(String id) : super(EntityType.ROLE, id); 6 | 7 | @override 8 | factory RoleId.fromJson(Map json) { 9 | return EntityId.fromJson(json) as RoleId; 10 | } 11 | 12 | @override 13 | String toString() { 14 | return 'RoleId {id: $id}'; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/src/model/id/user_id.dart: -------------------------------------------------------------------------------- 1 | import '../entity_type_models.dart'; 2 | import 'entity_id.dart'; 3 | 4 | class UserId extends EntityId { 5 | UserId(String id) : super(EntityType.USER, id); 6 | 7 | @override 8 | factory UserId.fromJson(Map json) { 9 | return EntityId.fromJson(json) as UserId; 10 | } 11 | 12 | @override 13 | String toString() { 14 | return 'UserId {id: $id}'; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Files and directories created by pub 2 | .dart_tool/ 3 | .packages 4 | 5 | # Omit commiting pubspec.lock for library packages: 6 | # https://dart.dev/guides/libraries/private-files#pubspeclock 7 | pubspec.lock 8 | 9 | # Conventional directory for build outputs 10 | build/ 11 | 12 | # Directory created by dartdoc 13 | doc/api/ 14 | 15 | *.iml 16 | */.idea/** 17 | .idea/** 18 | .idea 19 | 20 | tb_client_storage.json 21 | -------------------------------------------------------------------------------- /lib/src/model/id/alarm_id.dart: -------------------------------------------------------------------------------- 1 | import '../entity_type_models.dart'; 2 | import 'entity_id.dart'; 3 | 4 | class AlarmId extends EntityId { 5 | AlarmId(String id) : super(EntityType.ALARM, id); 6 | 7 | @override 8 | factory AlarmId.fromJson(Map json) { 9 | return EntityId.fromJson(json) as AlarmId; 10 | } 11 | 12 | @override 13 | String toString() { 14 | return 'AlarmId {id: $id}'; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/src/model/id/asset_id.dart: -------------------------------------------------------------------------------- 1 | import '../entity_type_models.dart'; 2 | import 'entity_id.dart'; 3 | 4 | class AssetId extends EntityId { 5 | AssetId(String id) : super(EntityType.ASSET, id); 6 | 7 | @override 8 | factory AssetId.fromJson(Map json) { 9 | return EntityId.fromJson(json) as AssetId; 10 | } 11 | 12 | @override 13 | String toString() { 14 | return 'AssetId {id: $id}'; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/src/model/id/queue_id.dart: -------------------------------------------------------------------------------- 1 | import '../entity_type_models.dart'; 2 | import 'entity_id.dart'; 3 | 4 | class QueueId extends EntityId { 5 | QueueId(String id) : super(EntityType.QUEUE, id); 6 | 7 | @override 8 | factory QueueId.fromJson(Map json) { 9 | return EntityId.fromJson(json) as QueueId; 10 | } 11 | 12 | @override 13 | String toString() { 14 | return 'QueueId {id: $id}'; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/src/model/id/alarm_comment_id.dart: -------------------------------------------------------------------------------- 1 | import 'has_uuid.dart'; 2 | 3 | class AlarmCommentId extends HasUuid { 4 | AlarmCommentId(String? id) : super(id); 5 | 6 | @override 7 | factory AlarmCommentId.fromJson(Map json) { 8 | return HasUuid.fromJson(json, (id) => AlarmCommentId(id)) as AlarmCommentId; 9 | } 10 | 11 | @override 12 | String toString() { 13 | return 'AlarmCommentId {id: $id}'; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/src/model/id/device_id.dart: -------------------------------------------------------------------------------- 1 | import '../entity_type_models.dart'; 2 | import 'entity_id.dart'; 3 | 4 | class DeviceId extends EntityId { 5 | DeviceId(String id) : super(EntityType.DEVICE, id); 6 | 7 | @override 8 | factory DeviceId.fromJson(Map json) { 9 | return EntityId.fromJson(json) as DeviceId; 10 | } 11 | 12 | @override 13 | String toString() { 14 | return 'DeviceId {id: $id}'; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/src/model/id/tenant_id.dart: -------------------------------------------------------------------------------- 1 | import '../entity_type_models.dart'; 2 | import 'entity_id.dart'; 3 | 4 | class TenantId extends EntityId { 5 | TenantId(String id) : super(EntityType.TENANT, id); 6 | 7 | @override 8 | factory TenantId.fromJson(Map json) { 9 | return EntityId.fromJson(json) as TenantId; 10 | } 11 | 12 | @override 13 | String toString() { 14 | return 'TenantId {id: $id}'; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/src/model/id/customer_id.dart: -------------------------------------------------------------------------------- 1 | import '../entity_type_models.dart'; 2 | import 'entity_id.dart'; 3 | 4 | class CustomerId extends EntityId { 5 | CustomerId(String id) : super(EntityType.CUSTOMER, id); 6 | 7 | @override 8 | factory CustomerId.fromJson(Map json) { 9 | return EntityId.fromJson(json) as CustomerId; 10 | } 11 | 12 | @override 13 | String toString() { 14 | return 'CustomerId {id: $id}'; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/src/model/id/rule_node_id.dart: -------------------------------------------------------------------------------- 1 | import '../entity_type_models.dart'; 2 | import 'entity_id.dart'; 3 | 4 | class RuleNodeId extends EntityId { 5 | RuleNodeId(String id) : super(EntityType.RULE_NODE, id); 6 | 7 | @override 8 | factory RuleNodeId.fromJson(Map json) { 9 | return EntityId.fromJson(json) as RuleNodeId; 10 | } 11 | 12 | @override 13 | String toString() { 14 | return 'RuleNodeId {id: $id}'; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/src/model/id/admin_settings_id.dart: -------------------------------------------------------------------------------- 1 | import 'has_uuid.dart'; 2 | 3 | class AdminSettingsId extends HasUuid { 4 | AdminSettingsId(String? id) : super(id); 5 | 6 | @override 7 | factory AdminSettingsId.fromJson(Map json) { 8 | return HasUuid.fromJson(json, (id) => AdminSettingsId(id)) 9 | as AdminSettingsId; 10 | } 11 | 12 | @override 13 | String toString() { 14 | return 'AdminSettingsId {id: $id}'; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/src/model/id/converter_id.dart: -------------------------------------------------------------------------------- 1 | import '../entity_type_models.dart'; 2 | import 'entity_id.dart'; 3 | 4 | class ConverterId extends EntityId { 5 | ConverterId(String id) : super(EntityType.CONVERTER, id); 6 | 7 | @override 8 | factory ConverterId.fromJson(Map json) { 9 | return EntityId.fromJson(json) as ConverterId; 10 | } 11 | 12 | @override 13 | String toString() { 14 | return 'ConverterId {id: $id}'; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/src/model/id/dashboard_id.dart: -------------------------------------------------------------------------------- 1 | import '../entity_type_models.dart'; 2 | import 'entity_id.dart'; 3 | 4 | class DashboardId extends EntityId { 5 | DashboardId(String id) : super(EntityType.DASHBOARD, id); 6 | 7 | @override 8 | factory DashboardId.fromJson(Map json) { 9 | return EntityId.fromJson(json) as DashboardId; 10 | } 11 | 12 | @override 13 | String toString() { 14 | return 'DashboardId {id: $id}'; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/src/model/id/rule_chain_id.dart: -------------------------------------------------------------------------------- 1 | import '../entity_type_models.dart'; 2 | import 'entity_id.dart'; 3 | 4 | class RuleChainId extends EntityId { 5 | RuleChainId(String id) : super(EntityType.RULE_CHAIN, id); 6 | 7 | @override 8 | factory RuleChainId.fromJson(Map json) { 9 | return EntityId.fromJson(json) as RuleChainId; 10 | } 11 | 12 | @override 13 | String toString() { 14 | return 'RuleChainId {id: $id}'; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/src/model/id/blob_entity_id.dart: -------------------------------------------------------------------------------- 1 | import '../entity_type_models.dart'; 2 | import 'entity_id.dart'; 3 | 4 | class BlobEntityId extends EntityId { 5 | BlobEntityId(String id) : super(EntityType.BLOB_ENTITY, id); 6 | 7 | @override 8 | factory BlobEntityId.fromJson(Map json) { 9 | return EntityId.fromJson(json) as BlobEntityId; 10 | } 11 | 12 | @override 13 | String toString() { 14 | return 'BlobEntityId {id: $id}'; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/src/model/id/entity_view_id.dart: -------------------------------------------------------------------------------- 1 | import '../entity_type_models.dart'; 2 | import 'entity_id.dart'; 3 | 4 | class EntityViewId extends EntityId { 5 | EntityViewId(String id) : super(EntityType.ENTITY_VIEW, id); 6 | 7 | @override 8 | factory EntityViewId.fromJson(Map json) { 9 | return EntityId.fromJson(json) as EntityViewId; 10 | } 11 | 12 | @override 13 | String toString() { 14 | return 'EntityViewId {id: $id}'; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/src/model/id/ota_package_id.dart: -------------------------------------------------------------------------------- 1 | import '../entity_type_models.dart'; 2 | import 'entity_id.dart'; 3 | 4 | class OtaPackageId extends EntityId { 5 | OtaPackageId(String id) : super(EntityType.OTA_PACKAGE, id); 6 | 7 | @override 8 | factory OtaPackageId.fromJson(Map json) { 9 | return EntityId.fromJson(json) as OtaPackageId; 10 | } 11 | 12 | @override 13 | String toString() { 14 | return 'OtaPackageId {id: $id}'; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/src/model/id/tb_resource_id.dart: -------------------------------------------------------------------------------- 1 | import '../entity_type_models.dart'; 2 | import 'entity_id.dart'; 3 | 4 | class TbResourceId extends EntityId { 5 | TbResourceId(String id) : super(EntityType.TB_RESOURCE, id); 6 | 7 | @override 8 | factory TbResourceId.fromJson(Map json) { 9 | return EntityId.fromJson(json) as TbResourceId; 10 | } 11 | 12 | @override 13 | String toString() { 14 | return 'TbResourceId {id: $id}'; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/src/model/id/widget_type_id.dart: -------------------------------------------------------------------------------- 1 | import '../entity_type_models.dart'; 2 | import 'entity_id.dart'; 3 | 4 | class WidgetTypeId extends EntityId { 5 | WidgetTypeId(String id) : super(EntityType.WIDGET_TYPE, id); 6 | 7 | @override 8 | factory WidgetTypeId.fromJson(Map json) { 9 | return EntityId.fromJson(json) as WidgetTypeId; 10 | } 11 | 12 | @override 13 | String toString() { 14 | return 'WidgetTypeId {id: $id}'; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/src/model/id/entity_group_id.dart: -------------------------------------------------------------------------------- 1 | import '../entity_type_models.dart'; 2 | import 'entity_id.dart'; 3 | 4 | class EntityGroupId extends EntityId { 5 | EntityGroupId(String id) : super(EntityType.ENTITY_GROUP, id); 6 | 7 | @override 8 | factory EntityGroupId.fromJson(Map json) { 9 | return EntityId.fromJson(json) as EntityGroupId; 10 | } 11 | 12 | @override 13 | String toString() { 14 | return 'EntityGroupId {id: $id}'; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/src/model/id/integration_id.dart: -------------------------------------------------------------------------------- 1 | import '../entity_type_models.dart'; 2 | import 'entity_id.dart'; 3 | 4 | class IntegrationId extends EntityId { 5 | IntegrationId(String id) : super(EntityType.INTEGRATION, id); 6 | 7 | @override 8 | factory IntegrationId.fromJson(Map json) { 9 | return EntityId.fromJson(json) as IntegrationId; 10 | } 11 | 12 | @override 13 | String toString() { 14 | return 'IntegrationId {id: $id}'; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/src/model/id/asset_profile_id.dart: -------------------------------------------------------------------------------- 1 | import '../entity_type_models.dart'; 2 | import 'entity_id.dart'; 3 | 4 | class AssetProfileId extends EntityId { 5 | AssetProfileId(String id) : super(EntityType.ASSET_PROFILE, id); 6 | 7 | @override 8 | factory AssetProfileId.fromJson(Map json) { 9 | return EntityId.fromJson(json) as AssetProfileId; 10 | } 11 | 12 | @override 13 | String toString() { 14 | return 'AssetProfileId {id: $id}'; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/src/model/id/notification_id.dart: -------------------------------------------------------------------------------- 1 | import '../entity_type_models.dart'; 2 | import 'entity_id.dart'; 3 | 4 | class NotificationId extends EntityId { 5 | NotificationId(String id) : super(EntityType.NOTIFICATION, id); 6 | 7 | @override 8 | factory NotificationId.fromJson(Map json) { 9 | return EntityId.fromJson(json) as NotificationId; 10 | } 11 | 12 | @override 13 | String toString() { 14 | return 'NotificationId {id: $id}'; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # Defines a default set of lint rules enforced for 2 | # projects at Google. For details and rationale, 3 | # see https://github.com/dart-lang/pedantic#enabled-lints. 4 | include: package:lints/core.yaml 5 | 6 | # For lint rules and documentation, see http://dart-lang.github.io/linter/lints. 7 | # Uncomment to specify additional rules. 8 | # linter: 9 | # rules: 10 | # - camel_case_types 11 | 12 | analyzer: 13 | # exclude: 14 | # - path/to/excluded/files/** 15 | -------------------------------------------------------------------------------- /lib/src/model/id/api_usage_state_id.dart: -------------------------------------------------------------------------------- 1 | import '../entity_type_models.dart'; 2 | import 'entity_id.dart'; 3 | 4 | class ApiUsageStateId extends EntityId { 5 | ApiUsageStateId(String id) : super(EntityType.API_USAGE_STATE, id); 6 | 7 | @override 8 | factory ApiUsageStateId.fromJson(Map json) { 9 | return EntityId.fromJson(json) as ApiUsageStateId; 10 | } 11 | 12 | @override 13 | String toString() { 14 | return 'ApiUsageStateId {id: $id}'; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/src/model/id/device_credentials_id.dart: -------------------------------------------------------------------------------- 1 | import 'has_uuid.dart'; 2 | 3 | class DeviceCredentialsId extends HasUuid { 4 | DeviceCredentialsId(String? id) : super(id); 5 | 6 | @override 7 | factory DeviceCredentialsId.fromJson(Map json) { 8 | return HasUuid.fromJson(json, (id) => DeviceCredentialsId(id)) 9 | as DeviceCredentialsId; 10 | } 11 | 12 | @override 13 | String toString() { 14 | return 'DeviceCredentialsId {id: $id}'; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/src/model/id/device_profile_id.dart: -------------------------------------------------------------------------------- 1 | import '../entity_type_models.dart'; 2 | import 'entity_id.dart'; 3 | 4 | class DeviceProfileId extends EntityId { 5 | DeviceProfileId(String id) : super(EntityType.DEVICE_PROFILE, id); 6 | 7 | @override 8 | factory DeviceProfileId.fromJson(Map json) { 9 | return EntityId.fromJson(json) as DeviceProfileId; 10 | } 11 | 12 | @override 13 | String toString() { 14 | return 'DeviceProfileId {id: $id}'; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/src/model/id/tenant_profile_id.dart: -------------------------------------------------------------------------------- 1 | import '../entity_type_models.dart'; 2 | import 'entity_id.dart'; 3 | 4 | class TenantProfileId extends EntityId { 5 | TenantProfileId(String id) : super(EntityType.TENANT_PROFILE, id); 6 | 7 | @override 8 | factory TenantProfileId.fromJson(Map json) { 9 | return EntityId.fromJson(json) as TenantProfileId; 10 | } 11 | 12 | @override 13 | String toString() { 14 | return 'TenantProfileId {id: $id}'; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/src/model/id/widgets_bundle_id.dart: -------------------------------------------------------------------------------- 1 | import '../entity_type_models.dart'; 2 | import 'entity_id.dart'; 3 | 4 | class WidgetsBundleId extends EntityId { 5 | WidgetsBundleId(String id) : super(EntityType.WIDGETS_BUNDLE, id); 6 | 7 | @override 8 | factory WidgetsBundleId.fromJson(Map json) { 9 | return EntityId.fromJson(json) as WidgetsBundleId; 10 | } 11 | 12 | @override 13 | String toString() { 14 | return 'WidgetsBundleId {id: $id}'; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/src/model/id/scheduler_event_id.dart: -------------------------------------------------------------------------------- 1 | import '../entity_type_models.dart'; 2 | import 'entity_id.dart'; 3 | 4 | class SchedulerEventId extends EntityId { 5 | SchedulerEventId(String id) : super(EntityType.SCHEDULER_EVENT, id); 6 | 7 | @override 8 | factory SchedulerEventId.fromJson(Map json) { 9 | return EntityId.fromJson(json) as SchedulerEventId; 10 | } 11 | 12 | @override 13 | String toString() { 14 | return 'SchedulerEventId {id: $id}'; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/src/model/id/component_descriptor_id.dart: -------------------------------------------------------------------------------- 1 | import 'has_uuid.dart'; 2 | 3 | class ComponentDescriptorId extends HasUuid { 4 | ComponentDescriptorId(String? id) : super(id); 5 | 6 | @override 7 | factory ComponentDescriptorId.fromJson(Map json) { 8 | return HasUuid.fromJson(json, (id) => ComponentDescriptorId(id)) 9 | as ComponentDescriptorId; 10 | } 11 | 12 | @override 13 | String toString() { 14 | return 'ComponentDescriptorId {id: $id}'; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /test/thingsboard_client_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_pe_client/thingsboard_client.dart'; 2 | import 'package:test/test.dart'; 3 | 4 | void main() { 5 | group('A group of tests', () { 6 | ThingsboardClient? tbClient; 7 | 8 | setUp(() async { 9 | tbClient = ThingsboardClient('http://localhost:8080'); 10 | await tbClient!.init(); 11 | }); 12 | 13 | test('First Test', () { 14 | expect(tbClient!.getDeviceService(), isNot(null)); 15 | }); 16 | }); 17 | } 18 | -------------------------------------------------------------------------------- /lib/src/model/id/group_permission_id.dart: -------------------------------------------------------------------------------- 1 | import '../entity_type_models.dart'; 2 | import 'entity_id.dart'; 3 | 4 | class GroupPermissionId extends EntityId { 5 | GroupPermissionId(String id) : super(EntityType.GROUP_PERMISSION, id); 6 | 7 | @override 8 | factory GroupPermissionId.fromJson(Map json) { 9 | return EntityId.fromJson(json) as GroupPermissionId; 10 | } 11 | 12 | @override 13 | String toString() { 14 | return 'GroupPermissionId {id: $id}'; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/src/model/authority_enum.dart: -------------------------------------------------------------------------------- 1 | enum Authority { 2 | SYS_ADMIN, 3 | TENANT_ADMIN, 4 | CUSTOMER_USER, 5 | REFRESH_TOKEN, 6 | ANONYMOUS, 7 | PRE_VERIFICATION_TOKEN 8 | } 9 | 10 | Authority authorityFromString(String value) { 11 | return Authority.values.firstWhere( 12 | (e) => e.toString().split('.')[1].toUpperCase() == value.toUpperCase()); 13 | } 14 | 15 | extension AuthorityToString on Authority { 16 | String toShortString() { 17 | return toString().split('.').last; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/src/model/id/notification_rule_id.dart: -------------------------------------------------------------------------------- 1 | import '../entity_type_models.dart'; 2 | import 'entity_id.dart'; 3 | 4 | class NotificationRuleId extends EntityId { 5 | NotificationRuleId(String id) : super(EntityType.NOTIFICATION_RULE, id); 6 | 7 | @override 8 | factory NotificationRuleId.fromJson(Map json) { 9 | return EntityId.fromJson(json) as NotificationRuleId; 10 | } 11 | 12 | @override 13 | String toString() { 14 | return 'NotificationRuleId {id: $id}'; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/src/model/id/notification_target_id.dart: -------------------------------------------------------------------------------- 1 | import '../entity_type_models.dart'; 2 | import 'entity_id.dart'; 3 | 4 | class NotificationTargetId extends EntityId { 5 | NotificationTargetId(String id) : super(EntityType.NOTIFICATION_TARGET, id); 6 | 7 | @override 8 | factory NotificationTargetId.fromJson(Map json) { 9 | return EntityId.fromJson(json) as NotificationTargetId; 10 | } 11 | 12 | @override 13 | String toString() { 14 | return 'NotificationTargetId {id: $id}'; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/src/model/id/notification_request_id.dart: -------------------------------------------------------------------------------- 1 | import '../entity_type_models.dart'; 2 | import 'entity_id.dart'; 3 | 4 | class NotificationRequestId extends EntityId { 5 | NotificationRequestId(String id) : super(EntityType.NOTIFICATION_REQUEST, id); 6 | 7 | @override 8 | factory NotificationRequestId.fromJson(Map json) { 9 | return EntityId.fromJson(json) as NotificationRequestId; 10 | } 11 | 12 | @override 13 | String toString() { 14 | return 'NotificationRequestId {id: $id}'; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/src/model/id/notification_template_id.dart: -------------------------------------------------------------------------------- 1 | import '../entity_type_models.dart'; 2 | import 'entity_id.dart'; 3 | 4 | class NotificationTemplateId extends EntityId { 5 | NotificationTemplateId(String id) 6 | : super(EntityType.NOTIFICATION_TEMPLATE, id); 7 | 8 | @override 9 | factory NotificationTemplateId.fromJson(Map json) { 10 | return EntityId.fromJson(json) as NotificationTemplateId; 11 | } 12 | 13 | @override 14 | String toString() { 15 | return 'NotificationTemplateId {id: $id}'; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /lib/src/model/mobile/mobile_info_query.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_pe_client/thingsboard_client.dart' 2 | show PlatformType, PlatformTypeToString; 3 | 4 | class MobileInfoQuery { 5 | const MobileInfoQuery({ 6 | required this.packageName, 7 | required this.platformType, 8 | }); 9 | 10 | final String packageName; 11 | final PlatformType platformType; 12 | 13 | Map toQueryParameters() { 14 | return { 15 | 'pkgName': packageName, 16 | 'platform': platformType.toShortString(), 17 | }; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/src/model/mobile/store_info.dart: -------------------------------------------------------------------------------- 1 | class StoreInfo { 2 | const StoreInfo({ 3 | required this.appId, 4 | required this.sha256CertFingerprints, 5 | required this.storeLink, 6 | }); 7 | 8 | factory StoreInfo.fromJson(Map json) { 9 | return StoreInfo( 10 | appId: json['appId'], 11 | sha256CertFingerprints: json['sha256CertFingerprints'], 12 | storeLink: json['storeLink'], 13 | ); 14 | } 15 | 16 | final String? appId; 17 | final String? sha256CertFingerprints; 18 | final String? storeLink; 19 | } 20 | -------------------------------------------------------------------------------- /lib/src/model/entity_models.dart: -------------------------------------------------------------------------------- 1 | import 'id/entity_id.dart'; 2 | 3 | class EntityInfo { 4 | EntityId id; 5 | String name; 6 | 7 | EntityInfo(this.id, this.name); 8 | 9 | EntityInfo.fromJson(Map json) 10 | : id = EntityId.fromJson(json['id']), 11 | name = json['name']; 12 | 13 | @override 14 | String toString() { 15 | return 'EntityInfo{${entityInfoString()}}'; 16 | } 17 | 18 | String entityInfoString([String? toStringBody]) { 19 | return 'id: $id, name: $name${toStringBody != null ? ', ' + toStringBody : ''}'; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lib/src/model/custom_translation_model.dart: -------------------------------------------------------------------------------- 1 | class CustomTranslation { 2 | Map? translationMap; 3 | 4 | CustomTranslation(this.translationMap); 5 | 6 | CustomTranslation.fromJson(Map json) 7 | : translationMap = json['translationMap']; 8 | 9 | Map toJson() { 10 | var json = {}; 11 | if (translationMap != null) { 12 | json['translationMap'] = translationMap; 13 | } 14 | return json; 15 | } 16 | 17 | @override 18 | String toString() { 19 | return 'CustomTranslation{translationMap: $translationMap}'; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lib/src/model/id/oauth2_client_registration_template_id.dart: -------------------------------------------------------------------------------- 1 | import 'has_uuid.dart'; 2 | 3 | class OAuth2ClientRegistrationTemplateId extends HasUuid { 4 | OAuth2ClientRegistrationTemplateId(String? id) : super(id); 5 | 6 | @override 7 | factory OAuth2ClientRegistrationTemplateId.fromJson( 8 | Map json) { 9 | return HasUuid.fromJson( 10 | json, (id) => OAuth2ClientRegistrationTemplateId(id)) 11 | as OAuth2ClientRegistrationTemplateId; 12 | } 13 | 14 | @override 15 | String toString() { 16 | return 'OAuth2ClientRegistrationTemplateId {id: $id}'; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lib/src/storage/in_memory_storage.dart: -------------------------------------------------------------------------------- 1 | import 'tb_storage.dart'; 2 | 3 | class InMemoryStorage implements TbStorage { 4 | final storageMap = {}; 5 | 6 | @override 7 | Future containsKey(String key) async { 8 | return storageMap.containsKey(key); 9 | } 10 | 11 | @override 12 | Future deleteItem(String key) async { 13 | storageMap.remove(key); 14 | } 15 | 16 | @override 17 | getItem(String key, {defaultValue}) async { 18 | return storageMap[key] ?? defaultValue; 19 | } 20 | 21 | @override 22 | Future setItem(String key, value) async { 23 | storageMap[key] = value; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lib/src/storage/tb_storage.dart: -------------------------------------------------------------------------------- 1 | abstract class TbStorage { 2 | /// Saves the [key] - [value] pair. 3 | Future setItem(String key, E value); 4 | 5 | /// Deletes the given [key] from the storage. 6 | /// 7 | /// If it does not exist, nothing happens. 8 | Future deleteItem(String key); 9 | 10 | /// Returns the value associated with the given [key]. If the key does not 11 | /// exist, `null` is returned. 12 | /// 13 | /// If [defaultValue] is specified, it is returned in case the key does not 14 | /// exist. 15 | Future? getItem(String key, {E? defaultValue}); 16 | 17 | /// Checks whether the storage contains the [key]. 18 | Future containsKey(String key); 19 | } 20 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: thingsboard_pe_client 2 | description: Dart implementation of ThingsBoard PE API client. Provides model objects and services to communicate with ThingsBoard PE platform using RESTful APIs and WebSocket protocol. 3 | version: 4.0.0 4 | homepage: https://thingsboard.io 5 | repository: https://github.com/thingsboard/dart_thingsboard_pe_client.git 6 | issue_tracker: https://github.com/thingsboard/dart_thingsboard_pe_client/issues 7 | 8 | environment: 9 | sdk: '>=3.2.0 <4.0.0' 10 | 11 | dependencies: 12 | collection: ^1.18.0 13 | dio: ^5.3.4 14 | jwt_decoder: ^2.0.1 15 | web_socket_channel: ^2.4.0 16 | pretty_dio_logger: ^1.4.0 17 | 18 | dev_dependencies: 19 | lints: ^3.0.0 20 | pedantic: ^1.11.1 21 | test: ^1.24.9 22 | -------------------------------------------------------------------------------- /example/thingsboard_pe_client.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_pe_client/thingsboard_client.dart'; 2 | 3 | const thingsBoardApiEndpoint = 'http://localhost:8080'; 4 | 5 | void main() async { 6 | try { 7 | var tbClient = ThingsboardClient(thingsBoardApiEndpoint); 8 | await tbClient.login(LoginRequest('tenant@thingsboard.org', 'tenant')); 9 | 10 | print('isAuthenticated=${tbClient.isAuthenticated()}'); 11 | 12 | print('authUser: ${tbClient.getAuthUser()}'); 13 | 14 | var currentUserDetails = await tbClient.getUserService().getUser(); 15 | print('currentUserDetails: $currentUserDetails'); 16 | 17 | await tbClient.logout(); 18 | } catch (e, s) { 19 | print('Error: $e'); 20 | print('Stack: $s'); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib/src/model/page/sort_order.dart: -------------------------------------------------------------------------------- 1 | enum Direction { ASC, DESC } 2 | 3 | extension DirectionToString on Direction { 4 | String toShortString() { 5 | return toString().split('.').last; 6 | } 7 | } 8 | 9 | class SortOrder { 10 | String property; 11 | Direction direction; 12 | SortOrder(this.property, this.direction); 13 | } 14 | 15 | SortOrder sortOrderFromString(String strSortOrder) { 16 | String property; 17 | var direction = Direction.ASC; 18 | if (strSortOrder.startsWith('-')) { 19 | direction = Direction.DESC; 20 | property = strSortOrder.substring(1); 21 | } else { 22 | if (strSortOrder.startsWith('+')) { 23 | property = strSortOrder.substring(1); 24 | } else { 25 | property = strSortOrder; 26 | } 27 | } 28 | return SortOrder(property, direction); 29 | } 30 | -------------------------------------------------------------------------------- /lib/src/model/id/has_uuid.dart: -------------------------------------------------------------------------------- 1 | import 'entity_id.dart'; 2 | 3 | const nullUuid = '13814000-1dd2-11b2-8080-808080808080'; 4 | 5 | abstract class HasUuid { 6 | String? id; 7 | 8 | HasUuid(this.id); 9 | 10 | factory HasUuid.fromJson(Map json, 11 | [FromIdFunction? fromId]) { 12 | if (json.containsKey('id')) { 13 | if (json.containsKey('entityType')) { 14 | return EntityId.fromJson(json); 15 | } else { 16 | String id = json['id']; 17 | return fromId!(id); 18 | } 19 | } else { 20 | throw FormatException('Missing id!'); 21 | } 22 | } 23 | 24 | bool isNullUid() => nullUuid == id; 25 | 26 | Map toJson() { 27 | return {'id': id}; 28 | } 29 | } 30 | 31 | typedef FromIdFunction = T Function(String id); 32 | -------------------------------------------------------------------------------- /lib/src/service/user_permissions_service.dart: -------------------------------------------------------------------------------- 1 | import '../model/security_models.dart'; 2 | 3 | import '../http/http_utils.dart'; 4 | import '../thingsboard_client_base.dart'; 5 | 6 | class UserPermissionsService { 7 | final ThingsboardClient _tbClient; 8 | 9 | factory UserPermissionsService(ThingsboardClient tbClient) { 10 | return UserPermissionsService._internal(tbClient); 11 | } 12 | 13 | UserPermissionsService._internal(this._tbClient); 14 | 15 | Future getAllowedPermissions( 16 | {RequestConfig? requestConfig}) async { 17 | var response = await _tbClient.get>( 18 | '/api/permissions/allowedPermissions', 19 | options: defaultHttpOptionsFromConfig(requestConfig)); 20 | return AllowedPermissionsInfo.fromJson(response.data!); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib/src/model/mobile/recaptcha_model.dart: -------------------------------------------------------------------------------- 1 | class RecaptchaModel { 2 | const RecaptchaModel({ 3 | required this.siteKey, 4 | required this.androidSiteKey, 5 | required this.iosSiteKey, 6 | required this.version, 7 | required this.projectId, 8 | this.logActionName, 9 | }); 10 | 11 | final String version; 12 | final String? logActionName; 13 | final String? androidSiteKey; 14 | final String? iosSiteKey; 15 | final String? projectId; 16 | final String? siteKey; 17 | 18 | factory RecaptchaModel.fromJson(Map json) { 19 | return RecaptchaModel( 20 | siteKey: json['siteKey'], 21 | androidSiteKey: json['androidKey'], 22 | iosSiteKey: json['iosKey'], 23 | projectId: json['projectId'], 24 | version: json['version'], 25 | logActionName: json['logActionName'], 26 | ); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lib/src/model/id/id_based.dart: -------------------------------------------------------------------------------- 1 | import 'has_id.dart'; 2 | import 'has_uuid.dart'; 3 | 4 | abstract class IdBased extends HasId { 5 | I? id; 6 | 7 | IdBased(); 8 | 9 | IdBased.fromJson(Map json, [FromIdFunction? fromId]) 10 | : id = json['id'] != null 11 | ? HasUuid.fromJson(json['id'], fromId) as I 12 | : null; 13 | 14 | Map toJson() { 15 | var json = {}; 16 | if (id != null) { 17 | json['id'] = id!.toJson(); 18 | } 19 | return json; 20 | } 21 | 22 | @override 23 | I? getId() { 24 | return id; 25 | } 26 | 27 | setId(I? id) { 28 | this.id = id; 29 | } 30 | 31 | @override 32 | String toString() { 33 | return 'IdBased{${idBasedString()}}'; 34 | } 35 | 36 | String idBasedString() { 37 | return 'id: $id'; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /lib/src/interceptor/interceptor_config.dart: -------------------------------------------------------------------------------- 1 | class InterceptorConfig { 2 | bool ignoreLoading = false; 3 | bool ignoreErrors = false; 4 | bool resendRequest = false; 5 | bool isRetry = false; 6 | 7 | InterceptorConfig( 8 | {this.ignoreLoading = false, 9 | this.ignoreErrors = false, 10 | this.resendRequest = false, 11 | this.isRetry = false}); 12 | 13 | InterceptorConfig.fromExtra(Map? extra) { 14 | if (extra != null) { 15 | ignoreLoading = extra['ignoreLoading'] ?? false; 16 | ignoreErrors = extra['ignoreErrors'] ?? false; 17 | resendRequest = extra['resendRequest'] ?? false; 18 | isRetry = extra['isRetry'] ?? false; 19 | } 20 | } 21 | 22 | Map toExtra() { 23 | return { 24 | 'ignoreLoading': ignoreLoading, 25 | 'ignoreErrors': ignoreErrors, 26 | 'resendRequest': resendRequest, 27 | 'isRetry': isRetry 28 | }; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /lib/src/model/mobile/mobile_version_info.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_pe_client/src/model/model.dart' 2 | show PlatformVersion; 3 | 4 | class MobileVersionInfo { 5 | const MobileVersionInfo({ 6 | required this.minVersion, 7 | required this.minVersionReleaseNotes, 8 | required this.latestVersion, 9 | required this.latestVersionReleaseNotes, 10 | }); 11 | 12 | factory MobileVersionInfo.fromJson(Map json) { 13 | return MobileVersionInfo( 14 | minVersion: PlatformVersion.fromString(json['minVersion']), 15 | minVersionReleaseNotes: json['minVersionReleaseNotes'], 16 | latestVersion: PlatformVersion.fromString(json['latestVersion']), 17 | latestVersionReleaseNotes: json['latestVersionReleaseNotes'], 18 | ); 19 | } 20 | 21 | final PlatformVersion minVersion; 22 | final String minVersionReleaseNotes; 23 | final PlatformVersion latestVersion; 24 | final String latestVersionReleaseNotes; 25 | } 26 | -------------------------------------------------------------------------------- /lib/src/model/login_models.dart: -------------------------------------------------------------------------------- 1 | import 'authority_enum.dart'; 2 | 3 | class LoginRequest { 4 | String username; 5 | String password; 6 | 7 | LoginRequest(this.username, this.password); 8 | 9 | Map toJson() { 10 | return { 11 | 'username': username, 12 | 'password': password, 13 | }; 14 | } 15 | } 16 | 17 | class LoginResponse { 18 | final String token; 19 | String? refreshToken; 20 | Authority? scope; 21 | 22 | LoginResponse(this.token, this.refreshToken); 23 | 24 | LoginResponse.fromJson(Map json) 25 | : token = json['token'], 26 | refreshToken = json['refreshToken'], 27 | scope = 28 | json['scope'] != null ? authorityFromString(json['scope']) : null; 29 | } 30 | 31 | class RefreshTokenRequest { 32 | final String refreshToken; 33 | 34 | RefreshTokenRequest(this.refreshToken); 35 | 36 | Map toJson() { 37 | return {'refreshToken': refreshToken}; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /lib/src/service/rule_engine_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:dio/dio.dart'; 2 | 3 | import '../thingsboard_client_base.dart'; 4 | import '../http/http_utils.dart'; 5 | import '../model/model.dart'; 6 | 7 | class RuleEngineService { 8 | final ThingsboardClient _tbClient; 9 | 10 | factory RuleEngineService(ThingsboardClient tbClient) { 11 | return RuleEngineService._internal(tbClient); 12 | } 13 | 14 | RuleEngineService._internal(this._tbClient); 15 | 16 | Future handleRuleEngineRequest(String requestBody, 17 | {EntityId? entityId, int? timeout, RequestConfig? requestConfig}) async { 18 | var url = '/api/rule-engine'; 19 | if (entityId != null) { 20 | url += '/${entityId.entityType.toShortString()}/${entityId.id}'; 21 | if (timeout != null) { 22 | url += '/$timeout'; 23 | } 24 | } 25 | var response = await _tbClient.post(url, 26 | data: requestBody, 27 | options: defaultHttpOptionsFromConfig(requestConfig)); 28 | return response.data; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /lib/src/service/owner_service.dart: -------------------------------------------------------------------------------- 1 | import '../thingsboard_client_base.dart'; 2 | import '../http/http_utils.dart'; 3 | import '../model/model.dart'; 4 | 5 | class OwnerService { 6 | final ThingsboardClient _tbClient; 7 | 8 | factory OwnerService(ThingsboardClient tbClient) { 9 | return OwnerService._internal(tbClient); 10 | } 11 | 12 | OwnerService._internal(this._tbClient); 13 | 14 | Future changeOwnerToTenant(String ownerId, EntityId entityId, 15 | {RequestConfig? requestConfig}) async { 16 | await _tbClient.post( 17 | '/api/owner/TENANT/$ownerId/${entityId.entityType.toShortString()}/${entityId.id}', 18 | options: defaultHttpOptionsFromConfig(requestConfig)); 19 | } 20 | 21 | Future changeOwnerToCustomer(String ownerId, EntityId entityId, 22 | {RequestConfig? requestConfig}) async { 23 | await _tbClient.post( 24 | '/api/owner/CUSTOMER/$ownerId/${entityId.entityType.toShortString()}/${entityId.id}', 25 | options: defaultHttpOptionsFromConfig(requestConfig)); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lib/src/model/mobile/mobile_self_registration_params.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_pe_client/thingsboard_client.dart' 2 | show RecaptchaModel, SignUpField; 3 | 4 | class MobileSelfRegistrationParams { 5 | const MobileSelfRegistrationParams({ 6 | required this.title, 7 | required this.recaptcha, 8 | required this.fields, 9 | required this.showPrivacyPolicy, 10 | required this.showTermsOfUse, 11 | }); 12 | 13 | final String? title; 14 | final RecaptchaModel recaptcha; 15 | final List fields; 16 | final bool showPrivacyPolicy; 17 | final bool showTermsOfUse; 18 | 19 | factory MobileSelfRegistrationParams.fromJson(Map json) { 20 | return MobileSelfRegistrationParams( 21 | title: json['title'], 22 | recaptcha: RecaptchaModel.fromJson(json['captcha']), 23 | fields: json['fields'] 24 | .map((e) => SignUpField.fromJson(e)) 25 | .toList(), 26 | showPrivacyPolicy: json['showPrivacyPolicy'], 27 | showTermsOfUse: json['showTermsOfUse'], 28 | ); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /lib/src/model/base_data.dart: -------------------------------------------------------------------------------- 1 | import 'id/has_uuid.dart'; 2 | import 'id/id_based.dart'; 3 | 4 | typedef FromJsonFunction = T Function(dynamic json); 5 | 6 | abstract class BaseData extends IdBased { 7 | int? createdTime; 8 | 9 | BaseData(); 10 | 11 | BaseData.fromJson(Map json, [FromIdFunction? fromId]) 12 | : createdTime = json['createdTime'], 13 | super.fromJson(json, fromId); 14 | 15 | @override 16 | Map toJson() { 17 | var json = super.toJson(); 18 | if (createdTime != null) { 19 | json['createdTime'] = createdTime; 20 | } 21 | return json; 22 | } 23 | 24 | @override 25 | String toString() { 26 | return 'BaseData{${baseDataString()}}'; 27 | } 28 | 29 | int? getCreatedTime() { 30 | return createdTime; 31 | } 32 | 33 | void setCreatedTime(int? createdTime) { 34 | this.createdTime = createdTime; 35 | } 36 | 37 | String baseDataString([String? toStringBody]) { 38 | return '${idBasedString()}, createdTime: $createdTime${toStringBody != null ? ', ' + toStringBody : ''}'; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /lib/src/model/mobile/pages_layout.dart: -------------------------------------------------------------------------------- 1 | enum Pages { 2 | home, 3 | alarms, 4 | devices, 5 | customers, 6 | assets, 7 | audit_logs, 8 | notifications, 9 | device_list, 10 | dashboards, 11 | undefined, 12 | } 13 | 14 | Pages pagesFromString(String? value) { 15 | return Pages.values.firstWhere( 16 | (e) => e.toString().split('.')[1].toUpperCase() == value?.toUpperCase(), 17 | orElse: () => Pages.undefined, 18 | ); 19 | } 20 | 21 | class PageLayout { 22 | const PageLayout({ 23 | this.id, 24 | this.label, 25 | this.icon, 26 | this.dashboardId, 27 | this.path, 28 | this.url, 29 | }); 30 | 31 | final Pages? id; 32 | final String? label; 33 | final String? icon; 34 | final String? dashboardId; 35 | final String? path; 36 | final String? url; 37 | 38 | factory PageLayout.fromJson(Map json) { 39 | return PageLayout( 40 | id: pagesFromString(json['id']), 41 | label: json['label'], 42 | icon: json['icon'], 43 | dashboardId: json['dashboardId'], 44 | path: json['path'], 45 | url: json['url'], 46 | ); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /lib/src/model/mobile/version_info.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_pe_client/src/model/model.dart' 2 | show PlatformVersion; 3 | 4 | class VersionInfo { 5 | const VersionInfo({ 6 | required this.minVersion, 7 | required this.minVersionReleaseNotes, 8 | required this.latestVersion, 9 | required this.latestVersionReleaseNotes, 10 | }); 11 | 12 | factory VersionInfo.fromJson(Map json) { 13 | return VersionInfo( 14 | minVersion: json['minVersion'] != null && json['minVersion'] != '' 15 | ? PlatformVersion.fromString(json['minVersion']) 16 | : null, 17 | minVersionReleaseNotes: json['minVersionReleaseNotes'], 18 | latestVersion: 19 | json['latestVersion'] != null && json['latestVersion'] != '' 20 | ? PlatformVersion.fromString(json['latestVersion']) 21 | : null, 22 | latestVersionReleaseNotes: json['latestVersionReleaseNotes'], 23 | ); 24 | } 25 | 26 | final PlatformVersion? minVersion; 27 | final String? minVersionReleaseNotes; 28 | final PlatformVersion? latestVersion; 29 | final String? latestVersionReleaseNotes; 30 | } 31 | -------------------------------------------------------------------------------- /lib/src/model/additional_info_based.dart: -------------------------------------------------------------------------------- 1 | import 'has_additional_info.dart'; 2 | 3 | import 'base_data.dart'; 4 | import 'id/has_uuid.dart'; 5 | 6 | abstract class AdditionalInfoBased extends BaseData 7 | with HasAdditionalInfo { 8 | Map? additionalInfo; 9 | 10 | AdditionalInfoBased(); 11 | 12 | AdditionalInfoBased.fromJson(Map json, 13 | [FromIdFunction? fromId]) 14 | : additionalInfo = json['additionalInfo'], 15 | super.fromJson(json, fromId); 16 | 17 | @override 18 | Map toJson() { 19 | var json = super.toJson(); 20 | if (additionalInfo != null) { 21 | json['additionalInfo'] = additionalInfo; 22 | } 23 | return json; 24 | } 25 | 26 | @override 27 | Map? getAdditionalInfo() { 28 | return additionalInfo; 29 | } 30 | 31 | @override 32 | String toString() { 33 | return 'AdditionalInfoBased{${additionalInfoBasedString()}}'; 34 | } 35 | 36 | String additionalInfoBasedString([String? toStringBody]) { 37 | return '${baseDataString('${toStringBody != null ? toStringBody + ',' : ''} additionalInfo: $additionalInfo')}'; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ThingsBoard PE API client library for Dart developers. Provides model objects and services to communicate with ThingsBoard PE platform using RESTful APIs and WebSocket protocol. 2 | Current client version is compatible with ThingsBoard PE starting from version 3.6.3PE. 3 | 4 | ## Usage 5 | 6 | A simple usage example: 7 | 8 | ```dart 9 | import 'package:thingsboard_pe_client/thingsboard_client.dart'; 10 | 11 | main() async { 12 | try { 13 | var tbClient = ThingsboardClient('https://thingsboard.cloud'); 14 | await tbClient.login(LoginRequest('tenant@thingsboard.org', 'tenant')); 15 | 16 | print('isAuthenticated=${tbClient.isAuthenticated()}'); 17 | 18 | print('authUser: ${tbClient.getAuthUser()}'); 19 | 20 | var currentUserDetails = await tbClient.getUserService().getUser(); 21 | print('currentUserDetails: $currentUserDetails'); 22 | 23 | await tbClient.logout(); 24 | 25 | } catch (e, s) { 26 | print('Error: $e'); 27 | print('Stack: $s'); 28 | } 29 | } 30 | ``` 31 | 32 | ## Features and bugs 33 | 34 | Please file feature requests and bugs at the [issue tracker][tracker]. 35 | 36 | [tracker]: https://github.com/thingsboard/dart_thingsboard_pe_client/issues 37 | -------------------------------------------------------------------------------- /lib/src/service/event_service.dart: -------------------------------------------------------------------------------- 1 | import '../thingsboard_client_base.dart'; 2 | import '../http/http_utils.dart'; 3 | import '../model/model.dart'; 4 | 5 | PageData parseEventPageData(Map json) { 6 | return PageData.fromJson(json, (json) => Event.fromJson(json)); 7 | } 8 | 9 | class EventService { 10 | final ThingsboardClient _tbClient; 11 | 12 | factory EventService(ThingsboardClient tbClient) { 13 | return EventService._internal(tbClient); 14 | } 15 | 16 | EventService._internal(this._tbClient); 17 | 18 | Future> getEvents( 19 | EntityId entityId, String tenantId, TimePageLink pageLink, 20 | {String? eventType, RequestConfig? requestConfig}) async { 21 | var url = 22 | '/api/events/${entityId.entityType.toShortString()}/${entityId.id}'; 23 | if (eventType != null) { 24 | url += '/$eventType'; 25 | } 26 | var queryParams = pageLink.toQueryParameters(); 27 | queryParams['tenantId'] = tenantId; 28 | var response = await _tbClient.get>(url, 29 | queryParameters: queryParams, 30 | options: defaultHttpOptionsFromConfig(requestConfig)); 31 | return _tbClient.compute(parseEventPageData, response.data!); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /lib/src/model/mobile/basic_mobile_info.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_pe_client/thingsboard_client.dart'; 2 | 3 | class MobileBasicInfo { 4 | const MobileBasicInfo({ 5 | required this.user, 6 | required this.homeDashboardInfo, 7 | required this.pages, 8 | required this.versionInfo, 9 | required this.storeInfo, 10 | }); 11 | 12 | factory MobileBasicInfo.fromJson(Map json) { 13 | return MobileBasicInfo( 14 | user: json['user'] != null ? User.fromJson(json['user']) : null, 15 | homeDashboardInfo: json['homeDashboardInfo'] != null 16 | ? HomeDashboardInfo.fromJson(json['homeDashboardInfo']) 17 | : null, 18 | pages: json['pages'] != null 19 | ? json['pages'] 20 | .map((e) => PageLayout.fromJson(e)) 21 | .toList() 22 | : null, 23 | storeInfo: json['storeInfo'] != null 24 | ? StoreInfo.fromJson(json['storeInfo']) 25 | : null, 26 | versionInfo: json['versionInfo'] != null 27 | ? VersionInfo.fromJson(json['versionInfo']) 28 | : null, 29 | ); 30 | } 31 | 32 | final User? user; 33 | final HomeDashboardInfo? homeDashboardInfo; 34 | final List? pages; 35 | final StoreInfo? storeInfo; 36 | final VersionInfo? versionInfo; 37 | } 38 | -------------------------------------------------------------------------------- /lib/src/model/mobile/login_mobile_info.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_pe_client/src/model/mobile/mobile_models.dart'; 2 | import 'package:thingsboard_pe_client/thingsboard_client.dart' 3 | show OAuth2ClientInfo; 4 | 5 | class LoginMobileInfo { 6 | const LoginMobileInfo({ 7 | required this.oAuth2Clients, 8 | required this.selfRegistrationParams, 9 | required this.storeInfo, 10 | required this.versionInfo, 11 | }); 12 | 13 | final List oAuth2Clients; 14 | final MobileSelfRegistrationParams? selfRegistrationParams; 15 | final StoreInfo? storeInfo; 16 | final VersionInfo? versionInfo; 17 | 18 | factory LoginMobileInfo.fromJson(Map json) { 19 | return LoginMobileInfo( 20 | oAuth2Clients: json['oAuth2ClientLoginInfos'] 21 | .map((e) => OAuth2ClientInfo.fromJson(e)) 22 | .toList(), 23 | selfRegistrationParams: json['selfRegistrationParams'] != null 24 | ? MobileSelfRegistrationParams.fromJson( 25 | json['selfRegistrationParams'], 26 | ) 27 | : null, 28 | storeInfo: json['storeInfo'] != null 29 | ? StoreInfo.fromJson(json['storeInfo']) 30 | : null, 31 | versionInfo: json['versionInfo'] != null 32 | ? VersionInfo.fromJson(json['versionInfo']) 33 | : null, 34 | ); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /lib/src/service/mobile_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_pe_client/thingsboard_client.dart'; 2 | 3 | class MobileService { 4 | MobileService._internal(this._tbClient); 5 | 6 | factory MobileService(ThingsboardClient tbClient) => 7 | MobileService._internal(tbClient); 8 | 9 | final ThingsboardClient _tbClient; 10 | 11 | Future getUserMobileInfo( 12 | MobileInfoQuery query, { 13 | RequestConfig? requestConfig, 14 | }) async { 15 | final queryParams = query.toQueryParameters(); 16 | final response = await _tbClient.get>( 17 | '/api/mobile', 18 | queryParameters: queryParams, 19 | options: defaultHttpOptionsFromConfig(requestConfig), 20 | ); 21 | 22 | return response.data != null 23 | ? MobileBasicInfo.fromJson(response.data!) 24 | : null; 25 | } 26 | 27 | Future getLoginMobileInfo( 28 | MobileInfoQuery query, { 29 | RequestConfig? requestConfig, 30 | }) async { 31 | final queryParams = query.toQueryParameters(); 32 | final response = await _tbClient.get>( 33 | '/api/noauth/mobile', 34 | queryParameters: queryParams, 35 | options: defaultHttpOptionsFromConfig(requestConfig), 36 | ); 37 | 38 | return response.data != null 39 | ? LoginMobileInfo.fromJson(response.data!) 40 | : null; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /lib/src/model/page/page_data.dart: -------------------------------------------------------------------------------- 1 | import '../base_data.dart'; 2 | 3 | class PageData { 4 | List data; 5 | int totalPages; 6 | int totalElements; 7 | bool hasNext; 8 | 9 | PageData(this.data, this.totalPages, this.totalElements, this.hasNext); 10 | 11 | PageData.fromJson(Map json, FromJsonFunction fromJson) 12 | : data = dataFromJson(json['data'], fromJson), 13 | totalPages = json['totalPages'], 14 | totalElements = json['totalElements'], 15 | hasNext = json['hasNext']; 16 | 17 | Map toJson() { 18 | return { 19 | 'data': data.map((dynamic e) => e.toJson()).toList(), 20 | 'totalPages': totalPages, 21 | 'totalElements': totalElements, 22 | 'hasNext': hasNext 23 | }; 24 | } 25 | 26 | @override 27 | String toString() { 28 | return 'PageData{data: ${dataToString(data)}, totalPages: $totalPages, totalElements: $totalElements, hasNext: $hasNext}'; 29 | } 30 | } 31 | 32 | PageData emptyPageData() => PageData([], 0, 0, false); 33 | 34 | List dataFromJson(List jsonData, FromJsonFunction fromJson) { 35 | return jsonData.map((e) => fromJson(e)).toList(); 36 | } 37 | 38 | String dataToString(List data) { 39 | var res = data.isNotEmpty ? '\n' : ''; 40 | res += data.map((e) => e.toString()).join('\n'); 41 | res += data.isNotEmpty ? '\n' : ''; 42 | return res; 43 | } 44 | -------------------------------------------------------------------------------- /lib/src/model/rpc_models.dart: -------------------------------------------------------------------------------- 1 | import 'base_data.dart'; 2 | import 'has_tenant_id.dart'; 3 | import 'id/device_id.dart'; 4 | import 'id/rpc_id.dart'; 5 | import 'id/tenant_id.dart'; 6 | 7 | enum RpcStatus { QUEUED, DELIVERED, SUCCESSFUL, TIMEOUT, FAILED } 8 | 9 | RpcStatus rpcStatusFromString(String value) { 10 | return RpcStatus.values.firstWhere( 11 | (e) => e.toString().split('.')[1].toUpperCase() == value.toUpperCase()); 12 | } 13 | 14 | extension RpcStatusToString on RpcStatus { 15 | String toShortString() { 16 | return toString().split('.').last; 17 | } 18 | } 19 | 20 | class Rpc extends BaseData with HasTenantId { 21 | TenantId tenantId; 22 | DeviceId deviceId; 23 | int expirationTime; 24 | dynamic request; 25 | dynamic response; 26 | RpcStatus status; 27 | 28 | Rpc.fromJson(Map json) 29 | : tenantId = TenantId.fromJson(json['tenantId']), 30 | deviceId = DeviceId.fromJson(json['deviceId']), 31 | expirationTime = json['expirationTime'], 32 | request = json['request'], 33 | response = json['response'], 34 | status = rpcStatusFromString(json['status']), 35 | super.fromJson(json); 36 | 37 | @override 38 | TenantId? getTenantId() { 39 | return tenantId; 40 | } 41 | 42 | @override 43 | String toString() { 44 | return 'Rpc{tenantId: $tenantId, deviceId: $deviceId, expirationTime: $expirationTime, request: $request, response: $response, status: $status}'; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /lib/src/model/id/ids.dart: -------------------------------------------------------------------------------- 1 | export 'admin_settings_id.dart'; 2 | export 'alarm_comment_id.dart'; 3 | export 'alarm_id.dart'; 4 | export 'api_usage_state_id.dart'; 5 | export 'asset_id.dart'; 6 | export 'audit_log_id.dart'; 7 | export 'customer_id.dart'; 8 | export 'dashboard_id.dart'; 9 | export 'device_credentials_id.dart'; 10 | export 'device_id.dart'; 11 | export 'device_profile_id.dart'; 12 | export 'asset_profile_id.dart'; 13 | export 'edge_id.dart'; 14 | export 'entity_id.dart'; 15 | export 'entity_view_id.dart'; 16 | export 'event_id.dart'; 17 | export 'notification_id.dart'; 18 | export 'notification_request_id.dart'; 19 | export 'notification_rule_id.dart'; 20 | export 'notification_target_id.dart'; 21 | export 'notification_template_id.dart'; 22 | export 'ota_package_id.dart'; 23 | export 'has_uuid.dart'; 24 | export 'rule_chain_id.dart'; 25 | export 'rule_node_id.dart'; 26 | export 'tb_resource_id.dart'; 27 | export 'tenant_id.dart'; 28 | export 'tenant_profile_id.dart'; 29 | export 'user_id.dart'; 30 | export 'widget_type_id.dart'; 31 | export 'widgets_bundle_id.dart'; 32 | export 'component_descriptor_id.dart'; 33 | export 'oauth2_client_registration_template_id.dart'; 34 | export 'edge_event_id.dart'; 35 | export 'rpc_id.dart'; 36 | export 'blob_entity_id.dart'; 37 | export 'converter_id.dart'; 38 | export 'entity_group_id.dart'; 39 | export 'group_permission_id.dart'; 40 | export 'integration_id.dart'; 41 | export 'role_id.dart'; 42 | export 'scheduler_event_id.dart'; 43 | export 'queue_id.dart'; 44 | -------------------------------------------------------------------------------- /example/user_permissions.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_pe_client/thingsboard_client.dart'; 2 | 3 | const thingsBoardApiEndpoint = 'http://localhost:8080'; 4 | const username = 'tenant@thingsboard.org'; 5 | const password = 'tenant'; 6 | 7 | late ThingsboardClient tbClient; 8 | 9 | void main() async { 10 | try { 11 | tbClient = ThingsboardClient(thingsBoardApiEndpoint); 12 | 13 | await tbClient.login(LoginRequest(username, password)); 14 | 15 | await userPermissionsExample(); 16 | 17 | await tbClient.logout( 18 | requestConfig: RequestConfig(ignoreLoading: true, ignoreErrors: true)); 19 | } catch (e, s) { 20 | print('Error: $e'); 21 | print('Stack: $s'); 22 | } 23 | } 24 | 25 | Future userPermissionsExample() async { 26 | print( 27 | '**********************************************************************'); 28 | print( 29 | '* USER PERMISSIONS EXAMPLE *'); 30 | print( 31 | '**********************************************************************'); 32 | 33 | var allowedUserPermissions = 34 | await tbClient.getUserPermissionsService().getAllowedPermissions(); 35 | 36 | print('Allowed user permissions: ${allowedUserPermissions.userPermissions}'); 37 | 38 | print( 39 | 'Has generic devices read permission: ${allowedUserPermissions.hasGenericPermission(Resource.DEVICE, Operation.READ)}'); 40 | 41 | print( 42 | '**********************************************************************'); 43 | } 44 | -------------------------------------------------------------------------------- /lib/src/model/entity_type_models.dart: -------------------------------------------------------------------------------- 1 | import 'id/tenant_id.dart'; 2 | 3 | enum EntityType { 4 | TENANT, 5 | TENANT_PROFILE, 6 | CUSTOMER, 7 | USER, 8 | DASHBOARD, 9 | ASSET, 10 | DEVICE, 11 | DEVICE_PROFILE, 12 | ASSET_PROFILE, 13 | ALARM, 14 | ENTITY_GROUP, 15 | CONVERTER, 16 | INTEGRATION, 17 | RULE_CHAIN, 18 | RULE_NODE, 19 | SCHEDULER_EVENT, 20 | BLOB_ENTITY, 21 | EDGE, 22 | ENTITY_VIEW, 23 | WIDGETS_BUNDLE, 24 | WIDGET_TYPE, 25 | ROLE, 26 | GROUP_PERMISSION, 27 | API_USAGE_STATE, 28 | TB_RESOURCE, 29 | OTA_PACKAGE, 30 | RPC, 31 | QUEUE, 32 | NOTIFICATION_TARGET, 33 | NOTIFICATION_TEMPLATE, 34 | NOTIFICATION_REQUEST, 35 | NOTIFICATION, 36 | NOTIFICATION_RULE 37 | } 38 | 39 | EntityType entityTypeFromString(String value) { 40 | return EntityType.values.firstWhere( 41 | (e) => e.toString().split('.')[1].toUpperCase() == value.toUpperCase()); 42 | } 43 | 44 | extension EntityTypeToString on EntityType { 45 | String toShortString() { 46 | return toString().split('.').last; 47 | } 48 | } 49 | 50 | class EntitySubtype { 51 | TenantId tenantId; 52 | EntityType entityType; 53 | String type; 54 | 55 | EntitySubtype.fromJson(Map json) 56 | : tenantId = TenantId.fromJson(json['tenantId']), 57 | entityType = entityTypeFromString(json['entityType']), 58 | type = json['type']; 59 | 60 | @override 61 | String toString() { 62 | return 'EntitySubtype{tenantId: $tenantId, entityType: $entityType, type: $type}'; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2021 The ThingsBoard Authors 2 | 3 | Redistribution and use in source and binary forms, with or without modification, 4 | are permitted provided that the following conditions are met: 5 | 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above 9 | copyright notice, this list of conditions and the following 10 | disclaimer in the documentation and/or other materials provided 11 | with the distribution. 12 | * Neither the name of Google Inc. nor the names of its 13 | contributors may be used to endorse or promote products derived 14 | from this software without specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 20 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 23 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /example/callbacks.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:thingsboard_pe_client/thingsboard_client.dart'; 4 | 5 | const thingsBoardApiEndpoint = 'http://localhost:8080'; 6 | 7 | late ThingsboardClient tbClient; 8 | 9 | void main() async { 10 | try { 11 | tbClient = ThingsboardClient(thingsBoardApiEndpoint, 12 | storage: InMemoryStorage(), 13 | onUserLoaded: onUserLoaded, 14 | onError: onError, 15 | onLoadStarted: onLoadStarted, 16 | onLoadFinished: onLoadFinished); 17 | await tbClient.init(); 18 | } catch (e, s) { 19 | print('Error: $e'); 20 | print('Stack: $s'); 21 | } 22 | } 23 | 24 | void onError(ThingsboardError error) { 25 | print('onError: error=$error'); 26 | } 27 | 28 | void onLoadStarted() { 29 | print('ON LOAD STARTED!'); 30 | } 31 | 32 | void onLoadFinished() { 33 | print('ON LOAD FINISHED!'); 34 | } 35 | 36 | bool loginExecuted = false; 37 | 38 | Future onUserLoaded() async { 39 | try { 40 | print('onUserLoaded: isAuthenticated=${tbClient.isAuthenticated()}'); 41 | if (tbClient.isAuthenticated()) { 42 | print('authUser: ${tbClient.getAuthUser()}'); 43 | var currentUserDetails = await tbClient.getUserService().getUser(); 44 | print('currentUserDetails: $currentUserDetails'); 45 | await tbClient.logout( 46 | requestConfig: 47 | RequestConfig(ignoreLoading: true, ignoreErrors: true)); 48 | exit(0); 49 | } else { 50 | await tbClient.login(LoginRequest('tenant@thingsboard.org', 'tenant')); 51 | } 52 | } catch (e, s) { 53 | print('Error: $e'); 54 | print('Stack: $s'); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /lib/src/service/report_service.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:dio/dio.dart'; 4 | 5 | import '../thingsboard_client_base.dart'; 6 | import '../http/http_utils.dart'; 7 | import '../model/model.dart'; 8 | 9 | class ReportService { 10 | final ThingsboardClient _tbClient; 11 | 12 | factory ReportService(ThingsboardClient tbClient) { 13 | return ReportService._internal(tbClient); 14 | } 15 | 16 | ReportService._internal(this._tbClient); 17 | 18 | Future downloadDashboardReport( 19 | String dashboardId, ReportParams reportParams, 20 | {RequestConfig? requestConfig}) async { 21 | var options = defaultHttpOptionsFromConfig(requestConfig); 22 | options.responseType = ResponseType.stream; 23 | var response = await _tbClient.post( 24 | '/api/report/$dashboardId/download', 25 | data: jsonEncode(reportParams), 26 | options: options); 27 | return response.data; 28 | } 29 | 30 | Future downloadTestReport(ReportConfig reportConfig, 31 | {String? reportsServerEndpointUrl, RequestConfig? requestConfig}) async { 32 | var queryParams = {}; 33 | if (reportsServerEndpointUrl != null) { 34 | queryParams['reportsServerEndpointUrl'] = reportsServerEndpointUrl; 35 | } 36 | var options = defaultHttpOptionsFromConfig(requestConfig); 37 | options.responseType = ResponseType.stream; 38 | var response = await _tbClient.post('/api/report/test', 39 | queryParameters: queryParams, 40 | data: jsonEncode(reportConfig), 41 | options: options); 42 | return response.data; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /lib/src/service/service.dart: -------------------------------------------------------------------------------- 1 | export 'admin_service.dart'; 2 | export 'alarm_service.dart'; 3 | export 'asset_profile_service.dart'; 4 | export 'asset_service.dart'; 5 | export 'attribute_service.dart'; 6 | export 'audit_log_service.dart'; 7 | export 'blob_entity_service.dart'; 8 | export 'component_descriptor_service.dart'; 9 | export 'converter_service.dart'; 10 | export 'custom_menu_service.dart'; 11 | export 'custom_translation_service.dart'; 12 | export 'customer_service.dart'; 13 | export 'dashboard_service.dart'; 14 | export 'device_profile_service.dart'; 15 | export 'device_service.dart'; 16 | export 'edge_service.dart'; 17 | export 'entities_version_control_service.dart'; 18 | export 'entity_group_service.dart'; 19 | export 'entity_query_service.dart'; 20 | export 'entity_relation_service.dart'; 21 | export 'entity_view_service.dart'; 22 | export 'group_permission_service.dart'; 23 | export 'integration_service.dart'; 24 | export 'notifications_service.dart'; 25 | export 'oauth2_service.dart'; 26 | export 'ota_package_service.dart'; 27 | export 'owner_service.dart'; 28 | export 'queue_service.dart'; 29 | export 'report_service.dart'; 30 | export 'resource_service.dart'; 31 | export 'role_service.dart'; 32 | export 'rule_chain_service.dart'; 33 | export 'rule_engine_service.dart'; 34 | export 'scheduler_event_service.dart'; 35 | export 'self_register_service.dart'; 36 | export 'signup_service.dart'; 37 | export 'telemetry_websocket_service.dart'; 38 | export 'tenant_profile_service.dart'; 39 | export 'tenant_service.dart'; 40 | export 'two_factor_auth_service.dart'; 41 | export 'user_permissions_service.dart'; 42 | export 'user_service.dart'; 43 | export 'white_labeling_service.dart'; 44 | export 'widget_service.dart'; 45 | -------------------------------------------------------------------------------- /lib/src/model/page/page_link.dart: -------------------------------------------------------------------------------- 1 | import 'sort_order.dart'; 2 | 3 | class PageLink { 4 | String? textSearch; 5 | int pageSize; 6 | int page; 7 | SortOrder? sortOrder; 8 | 9 | PageLink(this.pageSize, [this.page = 0, this.textSearch, this.sortOrder]); 10 | 11 | PageLink nextPageLink() { 12 | return PageLink(pageSize, page + 1, textSearch, sortOrder); 13 | } 14 | 15 | Map toQueryParameters() { 16 | var queryParameters = {'pageSize': pageSize, 'page': page}; 17 | if (textSearch != null && textSearch!.isNotEmpty) { 18 | queryParameters['textSearch'] = textSearch!; 19 | } 20 | if (sortOrder != null) { 21 | queryParameters['sortProperty'] = sortOrder!.property; 22 | queryParameters['sortOrder'] = sortOrder!.direction.toShortString(); 23 | } 24 | return queryParameters; 25 | } 26 | } 27 | 28 | class TimePageLink extends PageLink { 29 | int? startTime; 30 | int? endTime; 31 | 32 | TimePageLink(int pageSize, 33 | [int page = 0, 34 | String? textSearch, 35 | SortOrder? sortOrder, 36 | this.startTime, 37 | this.endTime]) 38 | : super(pageSize, page, textSearch, sortOrder); 39 | 40 | @override 41 | TimePageLink nextPageLink() { 42 | return TimePageLink( 43 | pageSize, page + 1, textSearch, sortOrder, startTime, endTime); 44 | } 45 | 46 | @override 47 | Map toQueryParameters() { 48 | final queryParameters = super.toQueryParameters(); 49 | if (startTime != null) { 50 | queryParameters['startTime'] = startTime; 51 | } 52 | if (endTime != null) { 53 | queryParameters['endTime'] = endTime; 54 | } 55 | 56 | return queryParameters; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /lib/src/service/custom_menu_service.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import '../thingsboard_client_base.dart'; 4 | import '../http/http_utils.dart'; 5 | import '../model/model.dart'; 6 | 7 | class CustomMenuService { 8 | final ThingsboardClient _tbClient; 9 | 10 | factory CustomMenuService(ThingsboardClient tbClient) { 11 | return CustomMenuService._internal(tbClient); 12 | } 13 | 14 | CustomMenuService._internal(this._tbClient); 15 | 16 | Future getCustomMenu({RequestConfig? requestConfig}) async { 17 | return nullIfNotFound( 18 | (RequestConfig requestConfig) async { 19 | var response = await _tbClient.get>( 20 | '/api/customMenu/customMenu', 21 | options: defaultHttpOptionsFromConfig(requestConfig)); 22 | return response.data != null 23 | ? CustomMenu.fromJson(response.data!) 24 | : null; 25 | }, 26 | requestConfig: requestConfig, 27 | ); 28 | } 29 | 30 | Future getCurrentCustomMenu( 31 | {RequestConfig? requestConfig}) async { 32 | return nullIfNotFound( 33 | (RequestConfig requestConfig) async { 34 | var response = await _tbClient.get>( 35 | '/api/customMenu/currentCustomMenu', 36 | options: defaultHttpOptionsFromConfig(requestConfig)); 37 | return response.data != null 38 | ? CustomMenu.fromJson(response.data!) 39 | : null; 40 | }, 41 | requestConfig: requestConfig, 42 | ); 43 | } 44 | 45 | Future saveCustomMenu(CustomMenu customMenu, 46 | {RequestConfig? requestConfig}) async { 47 | var response = await _tbClient.post>( 48 | '/api/customMenu/customMenu', 49 | data: jsonEncode(customMenu), 50 | options: defaultHttpOptionsFromConfig(requestConfig)); 51 | return CustomMenu.fromJson(response.data!); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /lib/src/model/report_models.dart: -------------------------------------------------------------------------------- 1 | class ReportParams { 2 | final String? type; 3 | final String? state; 4 | final Map? timewindow; 5 | final String? timezone; 6 | 7 | ReportParams({this.type, this.state, this.timewindow, this.timezone}); 8 | 9 | Map toJson() { 10 | var json = {}; 11 | if (type != null) { 12 | json['type'] = type; 13 | } 14 | if (state != null) { 15 | json['state'] = state; 16 | } 17 | if (timewindow != null) { 18 | json['timewindow'] = timewindow; 19 | } 20 | if (timezone != null) { 21 | json['timezone'] = timezone; 22 | } 23 | return json; 24 | } 25 | } 26 | 27 | class ReportConfig extends ReportParams { 28 | final String baseUrl; 29 | final String dashboardId; 30 | final bool useDashboardTimewindow; 31 | final String namePattern; 32 | final bool? useCurrentUserCredentials; 33 | final String userId; 34 | 35 | ReportConfig( 36 | {required this.baseUrl, 37 | required this.dashboardId, 38 | required this.useDashboardTimewindow, 39 | required this.namePattern, 40 | required this.userId, 41 | this.useCurrentUserCredentials, 42 | String? type, 43 | String? state, 44 | Map? timewindow, 45 | String? timezone}) 46 | : super( 47 | type: type, 48 | state: state, 49 | timewindow: timewindow, 50 | timezone: timezone); 51 | 52 | @override 53 | Map toJson() { 54 | var json = super.toJson(); 55 | json['baseUrl'] = baseUrl; 56 | json['dashboardId'] = dashboardId; 57 | json['useDashboardTimewindow'] = useDashboardTimewindow; 58 | json['namePattern'] = namePattern; 59 | json['userId'] = userId; 60 | if (useCurrentUserCredentials != null) { 61 | json['useCurrentUserCredentials'] = useCurrentUserCredentials; 62 | } 63 | return json; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /lib/src/service/entity_query_service.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import '../http/http_utils.dart'; 4 | import '../model/page/page_data.dart'; 5 | import '../model/query/query_models.dart'; 6 | 7 | import '../thingsboard_client_base.dart'; 8 | 9 | PageData parseEntityDataPageData(Map json) { 10 | return PageData.fromJson(json, (json) => EntityData.fromJson(json)); 11 | } 12 | 13 | PageData parseAlarmDataPageData(Map json) { 14 | return PageData.fromJson(json, (json) => AlarmData.fromJson(json)); 15 | } 16 | 17 | class EntityQueryService { 18 | final ThingsboardClient _tbClient; 19 | 20 | factory EntityQueryService(ThingsboardClient tbClient) { 21 | return EntityQueryService._internal(tbClient); 22 | } 23 | 24 | EntityQueryService._internal(this._tbClient); 25 | 26 | Future countEntitiesByQuery(EntityCountQuery query, 27 | {RequestConfig? requestConfig}) async { 28 | var response = await _tbClient.post('/api/entitiesQuery/count', 29 | data: jsonEncode(query), 30 | options: defaultHttpOptionsFromConfig(requestConfig)); 31 | return response.data!; 32 | } 33 | 34 | Future> findEntityDataByQuery(EntityDataQuery query, 35 | {RequestConfig? requestConfig}) async { 36 | var response = await _tbClient.post>( 37 | '/api/entitiesQuery/find', 38 | data: jsonEncode(query), 39 | options: defaultHttpOptionsFromConfig(requestConfig)); 40 | return _tbClient.compute(parseEntityDataPageData, response.data!); 41 | } 42 | 43 | Future> findAlarmDataByQuery(AlarmDataQuery query, 44 | {RequestConfig? requestConfig}) async { 45 | var response = await _tbClient.post>( 46 | '/api/alarmsQuery/find', 47 | data: jsonEncode(query), 48 | options: defaultHttpOptionsFromConfig(requestConfig)); 49 | return _tbClient.compute(parseAlarmDataPageData, response.data!); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /lib/src/model/rule_node_models.dart: -------------------------------------------------------------------------------- 1 | import 'has_name.dart'; 2 | import 'id/rule_chain_id.dart'; 3 | import 'id/rule_node_id.dart'; 4 | import 'additional_info_based.dart'; 5 | 6 | class RuleNode extends AdditionalInfoBased with HasName { 7 | RuleChainId? ruleChainId; 8 | String type; 9 | String name; 10 | bool debugMode; 11 | bool? singletonMode; 12 | int? configurationVersion; 13 | Map? configuration; 14 | 15 | RuleNode( 16 | {required this.type, 17 | required this.name, 18 | this.debugMode = false, 19 | this.ruleChainId, 20 | this.singletonMode, 21 | this.configurationVersion, 22 | this.configuration}); 23 | 24 | RuleNode.fromJson(Map json) 25 | : ruleChainId = json['ruleChainId'] != null 26 | ? RuleChainId.fromJson(json['ruleChainId']) 27 | : null, 28 | type = json['type'], 29 | name = json['name'], 30 | debugMode = json['debugMode'], 31 | singletonMode = json['singletonMode'], 32 | configurationVersion = json['configurationVersion'], 33 | configuration = json['configuration'], 34 | super.fromJson(json); 35 | 36 | @override 37 | Map toJson() { 38 | var json = super.toJson(); 39 | if (ruleChainId != null) { 40 | json['ruleChainId'] = ruleChainId!.toJson(); 41 | } 42 | json['type'] = type; 43 | json['name'] = name; 44 | json['debugMode'] = debugMode; 45 | json['singletonMode'] = singletonMode; 46 | json['configurationVersion'] = configurationVersion; 47 | if (configuration != null) { 48 | json['configuration'] = configuration; 49 | } 50 | return json; 51 | } 52 | 53 | @override 54 | String getName() { 55 | return name; 56 | } 57 | 58 | @override 59 | String toString() { 60 | return 'RuleNode{${additionalInfoBasedString('ruleChainId: $ruleChainId, type: $type, name: $name, ' 61 | 'debugMode: $debugMode, singletonMode: $singletonMode, ' 62 | 'configurationVersion: $configurationVersion, configuration: $configuration')}}'; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /lib/src/service/custom_translation_service.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import '../thingsboard_client_base.dart'; 4 | import '../http/http_utils.dart'; 5 | import '../model/model.dart'; 6 | 7 | class CustomTranslationService { 8 | final ThingsboardClient _tbClient; 9 | 10 | factory CustomTranslationService(ThingsboardClient tbClient) { 11 | return CustomTranslationService._internal(tbClient); 12 | } 13 | 14 | CustomTranslationService._internal(this._tbClient); 15 | 16 | Future getCustomTranslation( 17 | {RequestConfig? requestConfig}) async { 18 | return nullIfNotFound( 19 | (RequestConfig requestConfig) async { 20 | var response = await _tbClient.get>( 21 | '/api/customTranslation/customTranslation', 22 | options: defaultHttpOptionsFromConfig(requestConfig)); 23 | return response.data != null 24 | ? CustomTranslation.fromJson(response.data!) 25 | : null; 26 | }, 27 | requestConfig: requestConfig, 28 | ); 29 | } 30 | 31 | Future getCurrentCustomTranslation( 32 | {RequestConfig? requestConfig}) async { 33 | return nullIfNotFound( 34 | (RequestConfig requestConfig) async { 35 | var response = await _tbClient.get>( 36 | '/api/customTranslation/currentCustomTranslation', 37 | options: defaultHttpOptionsFromConfig(requestConfig)); 38 | return response.data != null 39 | ? CustomTranslation.fromJson(response.data!) 40 | : null; 41 | }, 42 | requestConfig: requestConfig, 43 | ); 44 | } 45 | 46 | Future saveCustomTranslation( 47 | CustomTranslation customTranslation, 48 | {RequestConfig? requestConfig}) async { 49 | var response = await _tbClient.post>( 50 | '/api/customTranslation/customTranslation', 51 | data: jsonEncode(customTranslation), 52 | options: defaultHttpOptionsFromConfig(requestConfig)); 53 | return CustomTranslation.fromJson(response.data!); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /example/mfa.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'dart:io'; 3 | 4 | import 'package:thingsboard_pe_client/thingsboard_client.dart'; 5 | import 'package:collection/collection.dart'; 6 | 7 | const thingsBoardApiEndpoint = 'http://localhost:8080'; 8 | 9 | late ThingsboardClient tbClient; 10 | 11 | void main() async { 12 | try { 13 | tbClient = ThingsboardClient(thingsBoardApiEndpoint, onMfaAuth: onMfa); 14 | await tbClient.login(LoginRequest('tenant@thingsboard.org', 'tenant')); 15 | 16 | print('isAuthenticated=${tbClient.isAuthenticated()}'); 17 | 18 | print('authUser: ${tbClient.getAuthUser()}'); 19 | 20 | if (tbClient.isAuthenticated() && !tbClient.isPreVerificationToken()) { 21 | var currentUserDetails = await tbClient.getUserService().getUser(); 22 | print('currentUserDetails: $currentUserDetails'); 23 | await tbClient.logout(); 24 | } 25 | } catch (e, s) { 26 | print('Error: $e'); 27 | print('Stack: $s'); 28 | } 29 | } 30 | 31 | void onMfa() async { 32 | print('ON MULTI-FACTOR AUTHENTICATION!'); 33 | List providers = await tbClient 34 | .getTwoFactorAuthService() 35 | .getAvailableLoginTwoFaProviders(); 36 | print('Available providers: $providers'); 37 | var defaultProvider = 38 | providers.firstWhereOrNull((provider) => provider.isDefault); 39 | if (defaultProvider != null) { 40 | print('Default provider: $defaultProvider'); 41 | await tbClient 42 | .getTwoFactorAuthService() 43 | .requestTwoFaVerificationCode(defaultProvider.type); 44 | print('Verification code sent!'); 45 | print('Enter MFA code:'); 46 | var code = stdin.readLineSync(encoding: utf8); 47 | var mfaCode = code?.trim(); 48 | print('Code entered: $mfaCode'); 49 | await tbClient.checkTwoFaVerificationCode(defaultProvider.type, mfaCode!); 50 | 51 | print('isAuthenticated=${tbClient.isAuthenticated()}'); 52 | 53 | print('authUser: ${tbClient.getAuthUser()}'); 54 | 55 | var currentUserDetails = await tbClient.getUserService().getUser(); 56 | print('currentUserDetails: $currentUserDetails'); 57 | await tbClient.logout(); 58 | } else { 59 | await tbClient.logout(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /lib/src/error/thingsboard_error.dart: -------------------------------------------------------------------------------- 1 | export '_thingsboard_error_handler.dart' 2 | if (dart.library.io) '_thingsboard_error_handler_io.dart' 3 | if (dart.library.html) '_thingsboard_error_handler_html.dart'; 4 | 5 | abstract class ThingsBoardErrorCode { 6 | static const int general = 2; 7 | static const int authentication = 10; 8 | static const int jwtTokenExpired = 11; 9 | static const int tenantTrialExpired = 12; 10 | static const int credentialsExpired = 15; 11 | static const int permissionDenied = 20; 12 | static const int invalidArguments = 30; 13 | static const int badRequestParams = 31; 14 | static const int itemNotFound = 32; 15 | static const int tooManyRequests = 33; 16 | static const int tooManyUpdates = 34; 17 | } 18 | 19 | class ThingsboardError implements Exception { 20 | bool? refreshTokenPending; 21 | String? message; 22 | int? errorCode; 23 | int? status; 24 | dynamic error; 25 | 26 | ThingsboardError( 27 | {this.message, 28 | this.errorCode, 29 | this.status, 30 | this.refreshTokenPending, 31 | this.error}); 32 | 33 | ThingsboardError.fromJson(Map json) 34 | : message = ThingsboardError.parseMessage(json), 35 | status = json['status'], 36 | errorCode = json['errorCode']; 37 | 38 | static String parseMessage(Map json) { 39 | String? message = json['message']; 40 | if (message == null) { 41 | if (json['error'] != null) { 42 | if (json['path'] != null) { 43 | message = "Path '" + json['path'] + "': " + json["error"]; 44 | } else { 45 | message = json['error']; 46 | } 47 | } else { 48 | message = "Unknown error"; 49 | } 50 | } 51 | return message!; 52 | } 53 | 54 | StackTrace? _stackTrace; 55 | 56 | set stackTrace(StackTrace? stack) => _stackTrace = stack; 57 | 58 | StackTrace? getStackTrace() => _stackTrace; 59 | 60 | @override 61 | String toString() { 62 | var msg = 63 | 'ThingsboardError: message: [$message], errorCode: $errorCode, status: $status'; 64 | if (_stackTrace != null) { 65 | msg += '\n$_stackTrace'; 66 | } 67 | return msg; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /lib/src/model/exportable_entity.dart: -------------------------------------------------------------------------------- 1 | import 'model.dart'; 2 | 3 | abstract mixin class ExportableEntity { 4 | void setId(I? id); 5 | 6 | I? getExternalId(); 7 | 8 | void setExternalId(I? externalId); 9 | 10 | int? getCreatedTime(); 11 | 12 | void setCreatedTime(int? createdTime); 13 | 14 | void setTenantId(TenantId? tenantId); 15 | 16 | String getName(); 17 | 18 | factory ExportableEntity.fromTypeAndJson( 19 | EntityType entityType, Map json) { 20 | switch (entityType) { 21 | case EntityType.CUSTOMER: 22 | return Customer.fromJson(json) as ExportableEntity; 23 | case EntityType.DASHBOARD: 24 | return Dashboard.fromJson(json) as ExportableEntity; 25 | case EntityType.ASSET: 26 | return Asset.fromJson(json) as ExportableEntity; 27 | case EntityType.ASSET_PROFILE: 28 | return AssetProfile.fromJson(json) as ExportableEntity; 29 | case EntityType.DEVICE: 30 | return Device.fromJson(json) as ExportableEntity; 31 | case EntityType.DEVICE_PROFILE: 32 | return DeviceProfile.fromJson(json) as ExportableEntity; 33 | case EntityType.RULE_CHAIN: 34 | return RuleChain.fromJson(json) as ExportableEntity; 35 | case EntityType.ENTITY_VIEW: 36 | return EntityView.fromJson(json) as ExportableEntity; 37 | case EntityType.WIDGETS_BUNDLE: 38 | return WidgetsBundle.fromJson(json) as ExportableEntity; 39 | case EntityType.ENTITY_GROUP: 40 | return EntityGroup.fromJson(json) as ExportableEntity; 41 | case EntityType.CONVERTER: 42 | return Converter.fromJson(json) as ExportableEntity; 43 | case EntityType.INTEGRATION: 44 | return Integration.fromJson(json) as ExportableEntity; 45 | case EntityType.ROLE: 46 | return Role.fromJson(json) as ExportableEntity; 47 | default: 48 | throw FormatException('Not exportable entity type: $entityType!'); 49 | } 50 | } 51 | } 52 | 53 | abstract mixin class ExportableNoTenantIdEntity 54 | implements ExportableEntity { 55 | @override 56 | void setTenantId(TenantId? tenantId) {} 57 | } 58 | -------------------------------------------------------------------------------- /lib/src/model/signup_models.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_pe_client/src/model/model.dart'; 2 | 3 | enum SignUpFieldsId { 4 | email, 5 | password, 6 | repeat_password, 7 | first_name, 8 | last_name, 9 | phone, 10 | country, 11 | city, 12 | state, 13 | zip, 14 | address, 15 | address2, 16 | undefined, 17 | } 18 | 19 | SignUpFieldsId signUpFieldsIdFromString(String? value) { 20 | return SignUpFieldsId.values.firstWhere( 21 | (e) => e.toString().split('.')[1].toUpperCase() == value?.toUpperCase(), 22 | orElse: () => SignUpFieldsId.undefined, 23 | ); 24 | } 25 | 26 | extension SignUpFieldsIdToString on SignUpFieldsId { 27 | String toShortString() { 28 | return toString().split('.').last.toUpperCase(); 29 | } 30 | } 31 | 32 | class SignUpField { 33 | const SignUpField({ 34 | required this.id, 35 | required this.label, 36 | required this.required, 37 | }); 38 | 39 | final SignUpFieldsId id; 40 | final String label; 41 | final bool required; 42 | 43 | factory SignUpField.fromJson(Map json) { 44 | return SignUpField( 45 | id: signUpFieldsIdFromString(json['id']), 46 | label: json['label'], 47 | required: json['required'], 48 | ); 49 | } 50 | } 51 | 52 | class SignUpRequest { 53 | SignUpRequest({ 54 | required this.fields, 55 | required this.recaptchaResponse, 56 | required this.pkgName, 57 | required this.platform, 58 | required this.appSecret, 59 | }); 60 | 61 | final Map fields; 62 | String recaptchaResponse; 63 | String pkgName; 64 | PlatformType platform; 65 | String appSecret; 66 | 67 | Map toJson() { 68 | final json = { 69 | 'recaptchaResponse': recaptchaResponse, 70 | 'pkgName': pkgName, 71 | 'platform': platform.toShortString(), 72 | 'appSecret': appSecret, 73 | 'fields': fields.map((k, v) => MapEntry(k.toShortString(), v)), 74 | }; 75 | 76 | return json; 77 | } 78 | } 79 | 80 | enum SignUpResult { SUCCESS, INACTIVE_USER_EXISTS } 81 | 82 | SignUpResult signUpResultFromString(String value) { 83 | return SignUpResult.values.firstWhere( 84 | (e) => e.toString().split('.')[1].toUpperCase() == value.toUpperCase(), 85 | ); 86 | } 87 | -------------------------------------------------------------------------------- /lib/src/model/model.dart: -------------------------------------------------------------------------------- 1 | export 'additional_info_based.dart'; 2 | export 'alarm_models.dart'; 3 | export 'asset_models.dart'; 4 | export 'audit_log_models.dart'; 5 | export 'authority_enum.dart'; 6 | export 'base_data.dart'; 7 | export 'blob_entity_models.dart'; 8 | export 'component_descriptor_models.dart'; 9 | export 'constants.dart'; 10 | export 'contact_based_model.dart'; 11 | export 'converter_models.dart'; 12 | export 'custom_menu_models.dart'; 13 | export 'custom_translation_model.dart'; 14 | export 'customer_models.dart'; 15 | export 'dashboard_models.dart'; 16 | export 'device_models.dart'; 17 | export 'edge_models.dart'; 18 | export 'entity_group_models.dart'; 19 | export 'entity_models.dart'; 20 | export 'entity_type_models.dart'; 21 | export 'entity_view_models.dart'; 22 | export 'event_models.dart'; 23 | export 'exportable_entity.dart'; 24 | export 'group_permission_models.dart'; 25 | export 'has_additional_info.dart'; 26 | export 'has_customer_id.dart'; 27 | export 'has_name.dart'; 28 | export 'has_ota_package.dart'; 29 | export 'has_rule_engine_profile.dart'; 30 | export 'has_tenant_id.dart'; 31 | export 'id/ids.dart'; 32 | export 'integration_models.dart'; 33 | export 'login_models.dart'; 34 | export 'mobile/mobile_models.dart'; 35 | export 'mobile_session_models.dart'; 36 | export 'oauth2_models.dart'; 37 | export 'ota_models.dart'; 38 | export 'page/page_data.dart'; 39 | export 'page/page_link.dart'; 40 | export 'page/sort_order.dart'; 41 | export 'push_notification_models.dart'; 42 | export 'query/query_models.dart'; 43 | export 'queue_models.dart'; 44 | export 'relation_models.dart'; 45 | export 'report_models.dart'; 46 | export 'resource_models.dart'; 47 | export 'role_models.dart'; 48 | export 'rpc_models.dart'; 49 | export 'rule_chain_models.dart'; 50 | export 'rule_node_models.dart'; 51 | export 'scheduler_event_models.dart'; 52 | export 'security_models.dart'; 53 | export 'self_register_models.dart'; 54 | export 'settings_models.dart'; 55 | export 'signup_models.dart'; 56 | export 'telemetry_models.dart'; 57 | export 'tenant_models.dart'; 58 | export 'two_factor_auth_models.dart'; 59 | export 'user_models.dart'; 60 | export 'vc_models.dart'; 61 | export 'version.dart'; 62 | export 'white_labeling_models.dart'; 63 | export 'widget_models.dart'; 64 | export 'widgets_bundle_model.dart'; 65 | -------------------------------------------------------------------------------- /lib/src/service/component_descriptor_service.dart: -------------------------------------------------------------------------------- 1 | import '../../thingsboard_client.dart'; 2 | 3 | class ComponentDescriptorService { 4 | final ThingsboardClient _tbClient; 5 | 6 | factory ComponentDescriptorService(ThingsboardClient tbClient) { 7 | return ComponentDescriptorService._internal(tbClient); 8 | } 9 | 10 | ComponentDescriptorService._internal(this._tbClient); 11 | 12 | Future getComponentDescriptorByClazz( 13 | String componentDescriptorClazz, 14 | {RequestConfig? requestConfig}) async { 15 | return nullIfNotFound( 16 | (RequestConfig requestConfig) async { 17 | var response = await _tbClient.get>( 18 | '/api/component/$componentDescriptorClazz', 19 | options: defaultHttpOptionsFromConfig(requestConfig)); 20 | return response.data != null 21 | ? ComponentDescriptor.fromJson(response.data!) 22 | : null; 23 | }, 24 | requestConfig: requestConfig, 25 | ); 26 | } 27 | 28 | Future> getComponentDescriptorsByType( 29 | ComponentType componentType, 30 | {RuleChainType ruleChainType = RuleChainType.CORE, 31 | RequestConfig? requestConfig}) async { 32 | var response = await _tbClient.get>( 33 | '/api/components/${componentType.toShortString()}', 34 | queryParameters: {'ruleChainType': ruleChainType.toShortString()}, 35 | options: defaultHttpOptionsFromConfig(requestConfig)); 36 | return response.data!.map((e) => ComponentDescriptor.fromJson(e)).toList(); 37 | } 38 | 39 | Future> getComponentDescriptorsByTypes( 40 | List componentTypes, 41 | {RuleChainType ruleChainType = RuleChainType.CORE, 42 | RequestConfig? requestConfig}) async { 43 | var response = await _tbClient.get>('/api/components', 44 | queryParameters: { 45 | 'componentTypes': 46 | componentTypes.map((e) => e.toShortString()).join(','), 47 | 'ruleChainType': ruleChainType.toShortString() 48 | }, 49 | options: defaultHttpOptionsFromConfig(requestConfig)); 50 | return response.data!.map((e) => ComponentDescriptor.fromJson(e)).toList(); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /lib/src/model/contact_based_model.dart: -------------------------------------------------------------------------------- 1 | import 'customer_models.dart'; 2 | import 'entity_type_models.dart'; 3 | import 'tenant_models.dart'; 4 | 5 | import 'additional_info_based.dart'; 6 | import 'has_name.dart'; 7 | import 'id/ids.dart'; 8 | 9 | abstract class ContactBased extends AdditionalInfoBased 10 | with HasName { 11 | String? country; 12 | String? state; 13 | String? city; 14 | String? address; 15 | String? address2; 16 | String? zip; 17 | String? phone; 18 | String? email; 19 | 20 | ContactBased(); 21 | 22 | factory ContactBased.contactBasedFromJson(Map json) { 23 | var id = EntityId.fromJson(json['id']); 24 | if (id.entityType == EntityType.TENANT) { 25 | return Tenant.fromJson(json) as ContactBased; 26 | } else { 27 | return Customer.fromJson(json) as ContactBased; 28 | } 29 | } 30 | 31 | ContactBased.fromJson(Map json) 32 | : country = json['country'], 33 | state = json['state'], 34 | city = json['city'], 35 | address = json['address'], 36 | address2 = json['address2'], 37 | zip = json['zip'], 38 | phone = json['phone'], 39 | email = json['email'], 40 | super.fromJson(json); 41 | 42 | @override 43 | Map toJson() { 44 | var json = super.toJson(); 45 | if (country != null) { 46 | json['country'] = country; 47 | } 48 | if (state != null) { 49 | json['state'] = state; 50 | } 51 | if (city != null) { 52 | json['city'] = city; 53 | } 54 | if (address != null) { 55 | json['address'] = address; 56 | } 57 | if (address2 != null) { 58 | json['address2'] = address2; 59 | } 60 | if (zip != null) { 61 | json['zip'] = zip; 62 | } 63 | if (phone != null) { 64 | json['phone'] = phone; 65 | } 66 | if (email != null) { 67 | json['email'] = email; 68 | } 69 | return json; 70 | } 71 | 72 | @override 73 | String toString() { 74 | return 'ContactBased{${contactBasedString()}}'; 75 | } 76 | 77 | String contactBasedString([String? toStringBody]) { 78 | return '${additionalInfoBasedString('${toStringBody != null ? toStringBody + ', ' : ''}country: $country, state: $state, city: $city, address: $address, address2: $address2, zip: $zip, phone: $phone, email: $email')}'; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /example/device_api.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_pe_client/thingsboard_client.dart'; 2 | import 'example_utils.dart'; 3 | 4 | const thingsBoardApiEndpoint = 'http://localhost:8080'; 5 | const username = 'tenant@thingsboard.org'; 6 | const password = 'tenant'; 7 | 8 | late ThingsboardClient tbClient; 9 | 10 | void main() async { 11 | try { 12 | tbClient = ThingsboardClient(thingsBoardApiEndpoint); 13 | 14 | await tbClient.login(LoginRequest(username, password)); 15 | 16 | await deviceApiExample(); 17 | 18 | await tbClient.logout( 19 | requestConfig: RequestConfig(ignoreLoading: true, ignoreErrors: true)); 20 | } catch (e, s) { 21 | print('Error: $e'); 22 | print('Stack: $s'); 23 | } 24 | } 25 | 26 | Future deviceApiExample() async { 27 | print( 28 | '**********************************************************************'); 29 | print( 30 | '* DEVICE API EXAMPLE *'); 31 | print( 32 | '**********************************************************************'); 33 | 34 | var deviceName = getRandomString(30); 35 | 36 | var device = Device(deviceName, 'default'); 37 | device.additionalInfo = {'description': 'My test device!'}; 38 | var savedDevice = await tbClient.getDeviceService().saveDevice(device); 39 | print('savedDevice: $savedDevice'); 40 | var foundDevice = 41 | await tbClient.getDeviceService().getDevice(savedDevice.id!.id!); 42 | print('foundDevice: $foundDevice'); 43 | var res = await tbClient.getAttributeService().saveEntityAttributesV2( 44 | foundDevice!.id!, AttributeScope.SHARED_SCOPE.toShortString(), { 45 | 'targetTemperature': 22.4, 46 | 'targetHumidity': 57.8, 47 | 'array': [1, 2], 48 | 'json': {'test': 'work!'} 49 | }); 50 | print('Save attributes result: $res'); 51 | var attributes = await tbClient.getAttributeService().getAttributesByScope( 52 | foundDevice.id!, 53 | AttributeScope.SHARED_SCOPE.toShortString(), 54 | ['targetTemperature', 'targetHumidity', 'array', 'json']); 55 | print('Found device attributes: $attributes'); 56 | 57 | await tbClient.getDeviceService().deleteDevice(savedDevice.id!.id!); 58 | foundDevice = 59 | await tbClient.getDeviceService().getDevice(savedDevice.id!.id!); 60 | print('foundDevice: $foundDevice'); 61 | print( 62 | '**********************************************************************'); 63 | } 64 | -------------------------------------------------------------------------------- /lib/src/http/http_utils.dart: -------------------------------------------------------------------------------- 1 | import 'package:dio/dio.dart'; 2 | 3 | import '../error/thingsboard_error.dart'; 4 | import '../interceptor/interceptor_config.dart'; 5 | 6 | class RequestConfig { 7 | bool ignoreLoading; 8 | bool ignoreErrors; 9 | bool resendRequest; 10 | bool followRedirect; 11 | 12 | RequestConfig( 13 | {this.ignoreLoading = false, 14 | this.ignoreErrors = false, 15 | this.resendRequest = false, 16 | this.followRedirect = true}); 17 | } 18 | 19 | Options defaultHttpOptionsFromConfig(RequestConfig? config) { 20 | config ??= RequestConfig(); 21 | return defaultHttpOptions( 22 | ignoreLoading: config.ignoreLoading, 23 | ignoreErrors: config.ignoreErrors, 24 | resendRequest: config.resendRequest, 25 | followRedirect: config.followRedirect); 26 | } 27 | 28 | Options defaultHttpOptions( 29 | {bool ignoreLoading = false, 30 | bool ignoreErrors = false, 31 | bool resendRequest = false, 32 | bool followRedirect = true}) { 33 | var interceptorConfig = InterceptorConfig( 34 | ignoreLoading: ignoreLoading, 35 | ignoreErrors: ignoreErrors, 36 | resendRequest: resendRequest); 37 | var options = Options( 38 | headers: {'Content-Type': 'application/json'}, 39 | extra: interceptorConfig.toExtra(), 40 | followRedirects: followRedirect, 41 | maxRedirects: !followRedirect ? 0 : null); 42 | return options; 43 | } 44 | 45 | Future nullIfNotFound( 46 | Future Function(RequestConfig requestConfig) fetchFunction, 47 | {RequestConfig? requestConfig}) async { 48 | try { 49 | return await fetchFunction( 50 | requestConfig ?? RequestConfig(ignoreErrors: true)); 51 | } catch (e) { 52 | if (e is ThingsboardError && 53 | e.errorCode == ThingsBoardErrorCode.itemNotFound) { 54 | return null; 55 | } else { 56 | rethrow; 57 | } 58 | } 59 | } 60 | 61 | Future isSuccessful( 62 | Future> Function(RequestConfig requestConfig) 63 | requestFunction, 64 | {RequestConfig? requestConfig}) async { 65 | try { 66 | var response = await requestFunction( 67 | requestConfig ?? RequestConfig(ignoreErrors: true)); 68 | if (response.statusCode != null) { 69 | var seriesCode = response.statusCode! ~/ 100; 70 | return seriesCode == 2; 71 | } 72 | return false; 73 | } catch (e) { 74 | return false; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /lib/src/model/widgets_bundle_model.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | import 'base_data.dart'; 4 | import 'exportable_entity.dart'; 5 | import 'has_tenant_id.dart'; 6 | import 'id/tenant_id.dart'; 7 | import 'id/widgets_bundle_id.dart'; 8 | 9 | class WidgetsBundle extends BaseData 10 | with HasTenantId, ExportableEntity { 11 | TenantId? tenantId; 12 | String? alias; 13 | String title; 14 | String? image; 15 | String? description; 16 | WidgetsBundleId? externalId; 17 | 18 | WidgetsBundle(this.title); 19 | 20 | WidgetsBundle.fromJson(Map json) 21 | : tenantId = json['tenantId'] != null 22 | ? TenantId.fromJson(json['tenantId']) 23 | : null, 24 | alias = json['alias'], 25 | title = json['title'], 26 | image = json['image'], 27 | description = json['description'], 28 | externalId = json['externalId'] != null 29 | ? WidgetsBundleId.fromJson(json['externalId']) 30 | : null, 31 | super.fromJson(json); 32 | 33 | @override 34 | Map toJson() { 35 | var json = super.toJson(); 36 | json['title'] = title; 37 | if (tenantId != null) { 38 | json['tenantId'] = tenantId!.toJson(); 39 | } 40 | if (alias != null) { 41 | json['alias'] = alias; 42 | } 43 | if (image != null) { 44 | json['image'] = image; 45 | } 46 | if (description != null) { 47 | json['description'] = description; 48 | } 49 | if (externalId != null) { 50 | json['externalId'] = externalId!.toJson(); 51 | } 52 | return json; 53 | } 54 | 55 | @override 56 | String getName() { 57 | return title; 58 | } 59 | 60 | @override 61 | TenantId? getTenantId() { 62 | return tenantId; 63 | } 64 | 65 | @override 66 | void setTenantId(TenantId? tenantId) { 67 | this.tenantId = tenantId; 68 | } 69 | 70 | @override 71 | WidgetsBundleId? getExternalId() { 72 | return externalId; 73 | } 74 | 75 | @override 76 | void setExternalId(WidgetsBundleId? externalId) { 77 | this.externalId = externalId; 78 | } 79 | 80 | @override 81 | String toString() { 82 | return 'WidgetsBundle{${baseDataString('tenantId: $tenantId, alias: $alias, title: $title, image: ${image != null ? '[' + image!.substring(0, min(30, image!.length)) + '...]' : 'null'}, ' 83 | 'description: $description, externalId: $externalId')}}'; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /lib/src/service/role_service.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import '../thingsboard_client_base.dart'; 4 | import '../http/http_utils.dart'; 5 | import '../model/model.dart'; 6 | 7 | PageData parseRolePageData(Map json) { 8 | return PageData.fromJson(json, (json) => Role.fromJson(json)); 9 | } 10 | 11 | class RoleService { 12 | final ThingsboardClient _tbClient; 13 | 14 | factory RoleService(ThingsboardClient tbClient) { 15 | return RoleService._internal(tbClient); 16 | } 17 | 18 | RoleService._internal(this._tbClient); 19 | 20 | Future getRole(String roleId, {RequestConfig? requestConfig}) async { 21 | return nullIfNotFound( 22 | (RequestConfig requestConfig) async { 23 | var response = await _tbClient.get>( 24 | '/api/role/$roleId', 25 | options: defaultHttpOptionsFromConfig(requestConfig)); 26 | return response.data != null ? Role.fromJson(response.data!) : null; 27 | }, 28 | requestConfig: requestConfig, 29 | ); 30 | } 31 | 32 | Future saveRole(Role role, {RequestConfig? requestConfig}) async { 33 | var response = await _tbClient.post>('/api/role', 34 | data: jsonEncode(role), 35 | options: defaultHttpOptionsFromConfig(requestConfig)); 36 | return Role.fromJson(response.data!); 37 | } 38 | 39 | Future deleteRole(String roleId, {RequestConfig? requestConfig}) async { 40 | await _tbClient.delete('/api/role/$roleId', 41 | options: defaultHttpOptionsFromConfig(requestConfig)); 42 | } 43 | 44 | Future> getRoles(PageLink pageLink, 45 | {RoleType? type, RequestConfig? requestConfig}) async { 46 | var queryParams = pageLink.toQueryParameters(); 47 | if (type != null) { 48 | queryParams['type'] = type.toShortString(); 49 | } 50 | var response = await _tbClient.get>('/api/roles', 51 | queryParameters: queryParams, 52 | options: defaultHttpOptionsFromConfig(requestConfig)); 53 | return _tbClient.compute(parseRolePageData, response.data!); 54 | } 55 | 56 | Future> getRolesByIds(List roleIds, 57 | {RequestConfig? requestConfig}) async { 58 | var response = await _tbClient.get>('/api/roles', 59 | queryParameters: {'roleIds': roleIds.join(',')}, 60 | options: defaultHttpOptionsFromConfig(requestConfig)); 61 | return response.data!.map((e) => Role.fromJson(e)).toList(); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /lib/src/service/audit_log_service.dart: -------------------------------------------------------------------------------- 1 | import '../thingsboard_client_base.dart'; 2 | import '../http/http_utils.dart'; 3 | import '../model/model.dart'; 4 | 5 | PageData parseAuditLogPageData(Map json) { 6 | return PageData.fromJson(json, (json) => AuditLog.fromJson(json)); 7 | } 8 | 9 | class AuditLogService { 10 | final ThingsboardClient _tbClient; 11 | 12 | factory AuditLogService(ThingsboardClient tbClient) { 13 | return AuditLogService._internal(tbClient); 14 | } 15 | 16 | AuditLogService._internal(this._tbClient); 17 | 18 | Future> getAuditLogs(TimePageLink pageLink, 19 | {RequestConfig? requestConfig}) async { 20 | var queryParams = pageLink.toQueryParameters(); 21 | var response = await _tbClient.get>('/api/audit/logs', 22 | queryParameters: queryParams, 23 | options: defaultHttpOptionsFromConfig(requestConfig)); 24 | return _tbClient.compute(parseAuditLogPageData, response.data!); 25 | } 26 | 27 | Future> getAuditLogsByCustomerId( 28 | String customerId, TimePageLink pageLink, 29 | {RequestConfig? requestConfig}) async { 30 | var queryParams = pageLink.toQueryParameters(); 31 | var response = await _tbClient.get>( 32 | '/api/audit/logs/customer/$customerId', 33 | queryParameters: queryParams, 34 | options: defaultHttpOptionsFromConfig(requestConfig)); 35 | return _tbClient.compute(parseAuditLogPageData, response.data!); 36 | } 37 | 38 | Future> getAuditLogsByUserId( 39 | String userId, TimePageLink pageLink, 40 | {RequestConfig? requestConfig}) async { 41 | var queryParams = pageLink.toQueryParameters(); 42 | var response = await _tbClient.get>( 43 | '/api/audit/logs/user/$userId', 44 | queryParameters: queryParams, 45 | options: defaultHttpOptionsFromConfig(requestConfig)); 46 | return _tbClient.compute(parseAuditLogPageData, response.data!); 47 | } 48 | 49 | Future> getAuditLogsByEntityId( 50 | EntityId entityId, TimePageLink pageLink, 51 | {RequestConfig? requestConfig}) async { 52 | var queryParams = pageLink.toQueryParameters(); 53 | var response = await _tbClient.get>( 54 | '/api/audit/logs/entity/${entityId.entityType.toShortString()}/${entityId.id}', 55 | queryParameters: queryParams, 56 | options: defaultHttpOptionsFromConfig(requestConfig)); 57 | return _tbClient.compute(parseAuditLogPageData, response.data!); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /lib/src/model/component_descriptor_models.dart: -------------------------------------------------------------------------------- 1 | import 'base_data.dart'; 2 | import 'id/component_descriptor_id.dart'; 3 | 4 | enum ComponentType { ENRICHMENT, FILTER, TRANSFORMATION, ACTION, EXTERNAL } 5 | 6 | ComponentType componentTypeFromString(String value) { 7 | return ComponentType.values.firstWhere( 8 | (e) => e.toString().split('.')[1].toUpperCase() == value.toUpperCase()); 9 | } 10 | 11 | extension ComponentTypeToString on ComponentType { 12 | String toShortString() { 13 | return toString().split('.').last; 14 | } 15 | } 16 | 17 | enum ComponentScope { SYSTEM, TENANT } 18 | 19 | ComponentScope componentScopeFromString(String value) { 20 | return ComponentScope.values.firstWhere( 21 | (e) => e.toString().split('.')[1].toUpperCase() == value.toUpperCase()); 22 | } 23 | 24 | extension ComponentScopeToString on ComponentScope { 25 | String toShortString() { 26 | return toString().split('.').last; 27 | } 28 | } 29 | 30 | enum ComponentClusteringMode { USER_PREFERENCE, ENABLED, SINGLETON } 31 | 32 | ComponentClusteringMode componentClusteringModeFromString(String value) { 33 | return ComponentClusteringMode.values.firstWhere( 34 | (e) => e.toString().split('.')[1].toUpperCase() == value.toUpperCase()); 35 | } 36 | 37 | extension ComponentClusteringModeToString on ComponentClusteringMode { 38 | String toShortString() { 39 | return toString().split('.').last; 40 | } 41 | } 42 | 43 | class ComponentDescriptor extends BaseData { 44 | ComponentType type; 45 | ComponentScope scope; 46 | final ComponentClusteringMode clusteringMode; 47 | String name; 48 | String clazz; 49 | Map? configurationDescriptor; 50 | final int configurationVersion; 51 | String? actions; 52 | 53 | ComponentDescriptor.fromJson(Map json) 54 | : type = componentTypeFromString(json['type']), 55 | scope = componentScopeFromString(json['scope']), 56 | clusteringMode = 57 | componentClusteringModeFromString(json['clusteringMode']), 58 | name = json['name'], 59 | clazz = json['clazz'], 60 | configurationDescriptor = json['configurationDescriptor'], 61 | configurationVersion = json['configurationVersion'], 62 | actions = json['actions'], 63 | super.fromJson(json, (id) => ComponentDescriptorId(id)); 64 | 65 | @override 66 | String toString() { 67 | return 'ComponentDescriptor{${baseDataString('type: $type, scope: $scope, name: $name, clusteringMode: $clusteringMode, ' 68 | 'clazz: $clazz, configurationDescriptor: $configurationDescriptor, ' 69 | 'configurationVersion: $configurationVersion, actions: $actions')}}'; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /lib/src/model/blob_entity_models.dart: -------------------------------------------------------------------------------- 1 | import 'id/customer_id.dart'; 2 | import 'entity_type_models.dart'; 3 | import 'has_name.dart'; 4 | import 'id/entity_id.dart'; 5 | import 'id/has_uuid.dart'; 6 | import 'id/tenant_id.dart'; 7 | import 'additional_info_based.dart'; 8 | import 'has_owner_id.dart'; 9 | import 'has_customer_id.dart'; 10 | import 'id/blob_entity_id.dart'; 11 | import 'tenant_entity.dart'; 12 | 13 | class BlobEntityInfo extends AdditionalInfoBased 14 | implements HasName, TenantEntity, HasCustomerId, HasOwnerId { 15 | TenantId? tenantId; 16 | CustomerId? customerId; 17 | String name; 18 | String type; 19 | String contentType; 20 | 21 | BlobEntityInfo.fromJson(Map json) 22 | : tenantId = TenantId.fromJson(json['tenantId']), 23 | customerId = json['customerId'] != null 24 | ? CustomerId.fromJson(json['customerId']) 25 | : null, 26 | name = json['name'], 27 | type = json['type'], 28 | contentType = json['contentType'], 29 | super.fromJson(json); 30 | 31 | @override 32 | String getName() { 33 | return name; 34 | } 35 | 36 | @override 37 | TenantId? getTenantId() { 38 | return tenantId; 39 | } 40 | 41 | @override 42 | CustomerId? getCustomerId() { 43 | return customerId; 44 | } 45 | 46 | @override 47 | EntityType getEntityType() { 48 | return EntityType.BLOB_ENTITY; 49 | } 50 | 51 | @override 52 | EntityId? getOwnerId() { 53 | return customerId != null && !customerId!.isNullUid() 54 | ? customerId 55 | : tenantId; 56 | } 57 | 58 | @override 59 | void setOwnerId(EntityId entityId) { 60 | if (entityId.entityType == EntityType.CUSTOMER) { 61 | customerId = CustomerId(entityId.id!); 62 | } else { 63 | customerId = CustomerId(nullUuid); 64 | } 65 | } 66 | 67 | @override 68 | String toString() { 69 | return 'BlobEntityInfo{${blobEntityInfoString()}}'; 70 | } 71 | 72 | String blobEntityInfoString([String? toStringBody]) { 73 | return '${additionalInfoBasedString('tenantId: $tenantId, customerId: $customerId, name: $name, type: $type, ' 74 | 'contentType: $contentType${toStringBody != null ? ', ' + toStringBody : ''}')}'; 75 | } 76 | } 77 | 78 | class BlobEntityWithCustomerInfo extends BlobEntityInfo { 79 | String? customerTitle; 80 | bool? customerIsPublic; 81 | 82 | BlobEntityWithCustomerInfo.fromJson(Map json) 83 | : customerTitle = json['customerTitle'], 84 | customerIsPublic = json['customerIsPublic'], 85 | super.fromJson(json); 86 | 87 | @override 88 | String toString() { 89 | return 'BlobEntityWithCustomerInfo{${blobEntityInfoString('customerTitle: $customerTitle, customerIsPublic: $customerIsPublic')}}'; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /lib/src/model/version.dart: -------------------------------------------------------------------------------- 1 | class PlatformVersionMatcher { 2 | static const int minPlatformVersionInt = 3900; 3 | 4 | static bool isSupportedPlatformVersion( 5 | PlatformVersion platformVersion, { 6 | required String type, 7 | }) { 8 | if (type != 'PE' && type != 'PAAS') { 9 | return false; 10 | } 11 | 12 | try { 13 | if (platformVersion.versionInt() < minPlatformVersionInt) { 14 | return false; 15 | } 16 | } catch (e) { 17 | return false; 18 | } 19 | return true; 20 | } 21 | } 22 | 23 | class PlatformVersion { 24 | static RegExp versionRegExp = new RegExp(r"([\d|.]+)([A-Z]*)(-SNAPSHOT)?"); 25 | 26 | int major; 27 | int minor; 28 | int patch; 29 | int? minorPatch; 30 | String? versionCode; 31 | bool isSnapshot; 32 | 33 | PlatformVersion( 34 | {required this.major, 35 | required this.minor, 36 | required this.patch, 37 | this.minorPatch, 38 | this.versionCode, 39 | this.isSnapshot = false}); 40 | 41 | factory PlatformVersion.fromString(String version) { 42 | RegExpMatch? match = versionRegExp.firstMatch(version); 43 | if (match != null) { 44 | String? versionStr = match.group(1); 45 | if (versionStr != null) { 46 | List versionParts = versionStr.split("."); 47 | if (versionParts.length >= 3) { 48 | int major = int.parse(versionParts[0]); 49 | int minor = int.parse(versionParts[1]); 50 | int patch = int.parse(versionParts[2]); 51 | int? minorPatch; 52 | if (versionParts.length > 3) { 53 | minorPatch = int.parse(versionParts[3]); 54 | } 55 | String? versionCode = match.group(2); 56 | bool isSnapshot = match.group(3) != null; 57 | return PlatformVersion( 58 | major: major, 59 | minor: minor, 60 | patch: patch, 61 | minorPatch: minorPatch, 62 | versionCode: versionCode, 63 | isSnapshot: isSnapshot); 64 | } 65 | } 66 | } 67 | throw ArgumentError("Invalid platform version string: $version"); 68 | } 69 | 70 | int versionInt() { 71 | return this.major * 1000 + 72 | this.minor * 100 + 73 | this.patch * 10 + 74 | (this.minorPatch != null ? this.minorPatch! : 0); 75 | } 76 | 77 | String versionString() { 78 | String version = "$major.$minor.$patch"; 79 | if (this.minorPatch != null) { 80 | version += ".$minorPatch"; 81 | } 82 | if (versionCode != null && versionCode!.isNotEmpty) { 83 | version += "$versionCode"; 84 | } 85 | if (isSnapshot) { 86 | version += "-SNAPSHOT"; 87 | } 88 | return version; 89 | } 90 | 91 | @override 92 | String toString() { 93 | return versionString(); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /lib/src/service/queue_service.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import '../thingsboard_client_base.dart'; 4 | import '../http/http_utils.dart'; 5 | import '../model/model.dart'; 6 | 7 | PageData parseQueuePageData(Map json) { 8 | return PageData.fromJson(json, (json) => Queue.fromJson(json)); 9 | } 10 | 11 | class QueueService { 12 | final ThingsboardClient _tbClient; 13 | 14 | factory QueueService(ThingsboardClient tbClient) { 15 | return QueueService._internal(tbClient); 16 | } 17 | 18 | QueueService._internal(this._tbClient); 19 | 20 | Future getQueue(String queueId, 21 | {RequestConfig? requestConfig}) async { 22 | return nullIfNotFound( 23 | (RequestConfig requestConfig) async { 24 | var response = await _tbClient.get>( 25 | '/api/queues/$queueId', 26 | options: defaultHttpOptionsFromConfig(requestConfig)); 27 | return response.data != null ? Queue.fromJson(response.data!) : null; 28 | }, 29 | requestConfig: requestConfig, 30 | ); 31 | } 32 | 33 | Future getQueueByName(String queueName, 34 | {RequestConfig? requestConfig}) async { 35 | return nullIfNotFound( 36 | (RequestConfig requestConfig) async { 37 | var response = await _tbClient.get>( 38 | '/api/queues/name/$queueName', 39 | options: defaultHttpOptionsFromConfig(requestConfig)); 40 | return response.data != null ? Queue.fromJson(response.data!) : null; 41 | }, 42 | requestConfig: requestConfig, 43 | ); 44 | } 45 | 46 | Future saveQueue(Queue queue, ServiceType serviceType, 47 | {RequestConfig? requestConfig}) async { 48 | var queryParams = { 49 | 'serviceType': serviceType.toShortString() 50 | }; 51 | var response = await _tbClient.post>('/api/queues', 52 | queryParameters: queryParams, 53 | data: jsonEncode(queue), 54 | options: defaultHttpOptionsFromConfig(requestConfig)); 55 | return Queue.fromJson(response.data!); 56 | } 57 | 58 | Future deleteQueue(String queueId, 59 | {RequestConfig? requestConfig}) async { 60 | await _tbClient.delete('/api/queues/$queueId', 61 | options: defaultHttpOptionsFromConfig(requestConfig)); 62 | } 63 | 64 | Future> getTenantQueuesByServiceType( 65 | PageLink pageLink, ServiceType serviceType, 66 | {RequestConfig? requestConfig}) async { 67 | var queryParams = pageLink.toQueryParameters(); 68 | queryParams['serviceType'] = serviceType.toShortString(); 69 | var response = await _tbClient.get>('/api/queues', 70 | queryParameters: queryParams, 71 | options: defaultHttpOptionsFromConfig(requestConfig)); 72 | return _tbClient.compute(parseQueuePageData, response.data!); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /lib/src/model/resource_models.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | import 'has_name.dart'; 4 | import 'has_tenant_id.dart'; 5 | import 'id/tb_resource_id.dart'; 6 | import 'base_data.dart'; 7 | import 'id/tenant_id.dart'; 8 | 9 | enum ResourceType { LWM2M_MODEL, JKS, PKCS_12, JS_MODULE } 10 | 11 | ResourceType resourceTypeFromString(String value) { 12 | return ResourceType.values.firstWhere( 13 | (e) => e.toString().split('.')[1].toUpperCase() == value.toUpperCase()); 14 | } 15 | 16 | extension ResourceTypeToString on ResourceType { 17 | String toShortString() { 18 | return toString().split('.').last; 19 | } 20 | } 21 | 22 | class TbResourceInfo extends BaseData with HasName, HasTenantId { 23 | TenantId? tenantId; 24 | String title; 25 | ResourceType resourceType; 26 | String resourceKey; 27 | 28 | TbResourceInfo(this.title, this.resourceType, this.resourceKey); 29 | 30 | TbResourceInfo.fromJson(Map json) 31 | : tenantId = json['tenantId'] != null 32 | ? TenantId.fromJson(json['tenantId']) 33 | : null, 34 | title = json['title'], 35 | resourceType = resourceTypeFromString(json['resourceType']), 36 | resourceKey = json['resourceKey'], 37 | super.fromJson(json); 38 | 39 | @override 40 | Map toJson() { 41 | var json = super.toJson(); 42 | if (tenantId != null) { 43 | json['tenantId'] = tenantId!.toJson(); 44 | } 45 | json['title'] = title; 46 | json['resourceType'] = resourceType.toShortString(); 47 | json['resourceKey'] = resourceKey; 48 | return json; 49 | } 50 | 51 | @override 52 | TenantId? getTenantId() { 53 | return tenantId; 54 | } 55 | 56 | @override 57 | String getName() { 58 | return title; 59 | } 60 | 61 | @override 62 | String toString() { 63 | return 'TbResourceInfo{${resourceInfoString()}}'; 64 | } 65 | 66 | String resourceInfoString([String? toStringBody]) { 67 | return '${baseDataString('tenantId: $tenantId, title: $title, resourceType: ${resourceType.toShortString()}, resourceKey: $resourceKey${toStringBody != null ? ', ' + toStringBody : ''}')}'; 68 | } 69 | } 70 | 71 | class TbResource extends TbResourceInfo { 72 | String fileName; 73 | String data; 74 | 75 | TbResource(String title, ResourceType resourceType, String resourceKey, 76 | this.fileName, this.data) 77 | : super(title, resourceType, resourceKey); 78 | 79 | TbResource.fromJson(Map json) 80 | : fileName = json['fileName'], 81 | data = json['data'], 82 | super.fromJson(json); 83 | 84 | @override 85 | Map toJson() { 86 | var json = super.toJson(); 87 | json['fileName'] = fileName; 88 | json['data'] = data; 89 | return json; 90 | } 91 | 92 | @override 93 | String toString() { 94 | return 'TbResource{${resourceInfoString('fileName: $fileName, data: [${data.substring(0, min(30, data.length))}...]')}}'; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /lib/src/storage/_local_file_storage_io.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'dart:io'; 3 | import 'dart:typed_data'; 4 | 5 | import 'tb_storage.dart'; 6 | 7 | TbStorage createLocalFileStorage(String fileName, [String? path]) => 8 | LocalFileStorage(fileName, path); 9 | 10 | class LocalFileStorage implements TbStorage { 11 | late Future ready; 12 | 13 | LocalFileStorage(this.fileName, [this.path]) { 14 | ready = Future(() async { 15 | await _init(); 16 | return true; 17 | }); 18 | } 19 | 20 | final String? path; 21 | final String fileName; 22 | 23 | Map _data = {}; 24 | 25 | RandomAccessFile? _file; 26 | 27 | Future _init() async { 28 | _data = {}; 29 | 30 | final f = await _getFile(); 31 | final length = await f.length(); 32 | 33 | if (length == 0) { 34 | return _flush({}); 35 | } else { 36 | await _readFile(); 37 | } 38 | } 39 | 40 | @override 41 | Future deleteItem(String key) async { 42 | await ready; 43 | _data.remove(key); 44 | return _flush(); 45 | } 46 | 47 | @override 48 | Future getItem(String key, {dynamic defaultValue}) async { 49 | await ready; 50 | return _data[key]; 51 | } 52 | 53 | @override 54 | Future setItem(String key, dynamic value) async { 55 | await ready; 56 | _data[key] = value; 57 | return _flush(); 58 | } 59 | 60 | Future _flush([dynamic data]) async { 61 | final serialized = json.encode(data ?? _data); 62 | final buffer = utf8.encode(serialized); 63 | 64 | _file = await _file?.lock(); 65 | _file = await _file?.setPosition(0); 66 | _file = await _file?.writeFrom(buffer); 67 | _file = await _file?.truncate(buffer.length); 68 | await _file?.unlock(); 69 | } 70 | 71 | Future _readFile() async { 72 | var _file = await _getFile(); 73 | final length = await _file.length(); 74 | _file = await _file.setPosition(0); 75 | final buffer = Uint8List(length); 76 | await _file.readInto(buffer); 77 | final contentText = utf8.decode(buffer); 78 | 79 | _data = json.decode(contentText) as Map; 80 | } 81 | 82 | Future _getFile() async { 83 | if (_file != null) { 84 | return _file!; 85 | } 86 | 87 | final _path = path ?? _getDocumentDir().path; 88 | final file = File('$_path/$fileName'); 89 | 90 | if (await file.exists()) { 91 | _file = await file.open(mode: FileMode.append); 92 | } else { 93 | await file.create(); 94 | _file = await file.open(mode: FileMode.append); 95 | } 96 | 97 | return _file!; 98 | } 99 | 100 | Directory _getDocumentDir() { 101 | try { 102 | return Directory.current; 103 | } catch (err) { 104 | rethrow; 105 | } 106 | } 107 | 108 | @override 109 | Future containsKey(key) async { 110 | return _data.containsKey(key); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /example/ota_package.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'dart:math'; 3 | 4 | import 'package:dio/dio.dart'; 5 | import 'package:thingsboard_pe_client/thingsboard_client.dart'; 6 | 7 | import 'example_utils.dart'; 8 | 9 | const thingsBoardApiEndpoint = 'http://localhost:8080'; 10 | const username = 'tenant@thingsboard.org'; 11 | const password = 'tenant'; 12 | 13 | late ThingsboardClient tbClient; 14 | 15 | void main() async { 16 | try { 17 | tbClient = ThingsboardClient(thingsBoardApiEndpoint); 18 | 19 | await tbClient.login(LoginRequest(username, password)); 20 | 21 | await otaPackageExample(); 22 | 23 | await tbClient.logout( 24 | requestConfig: RequestConfig(ignoreLoading: true, ignoreErrors: true)); 25 | } catch (e, s) { 26 | print('Error: $e'); 27 | print('Stack: $s'); 28 | } 29 | } 30 | 31 | Future otaPackageExample() async { 32 | print( 33 | '**********************************************************************'); 34 | print( 35 | '* OTA PACKAGE EXAMPLE *'); 36 | print( 37 | '**********************************************************************'); 38 | 39 | var deviceProfileId = 40 | (await tbClient.getDeviceProfileService().getDefaultDeviceProfileInfo()) 41 | .id; 42 | 43 | var otaPackage = OtaPackageInfo(DeviceProfileId(deviceProfileId.id!), 44 | OtaPackageType.FIRMWARE, getRandomString(30), 'v.1'); 45 | otaPackage = 46 | await tbClient.getOtaPackageService().saveOtaPackageInfo(otaPackage); 47 | 48 | var file = MultipartFile.fromString('Test content', filename: 'test.txt'); 49 | otaPackage = await tbClient.getOtaPackageService().saveOtaPackageData( 50 | otaPackage.id!.id!, file, 51 | checksumAlgorithm: ChecksumAlgorithm.SHA256); 52 | 53 | print('download ota package with id: ${otaPackage.id!.id}'); 54 | var responseBody = await tbClient 55 | .getOtaPackageService() 56 | .downloadOtaPackage(otaPackage.id!.id!); 57 | if (responseBody != null) { 58 | var headers = Headers.fromMap(responseBody.headers); 59 | var contentLength = headers[Headers.contentLengthHeader]?.first ?? '-1'; 60 | var contentType = headers[Headers.contentTypeHeader]?.first ?? ''; 61 | var contentDisposition = headers['content-disposition']?.first ?? ''; 62 | print('download ota package contentLength: $contentLength'); 63 | print('download ota package contentType: $contentType'); 64 | print('download ota package contentDisposition: $contentDisposition'); 65 | var bytes = await responseBody.stream.toList(); 66 | bytes.forEach((bytes) { 67 | var base64str = base64Encode(bytes); 68 | print('download ota package chunk length: ${bytes.length}'); 69 | print( 70 | 'download ota package chunk bytes: [${base64str.substring(0, min(30, base64str.length))}...]'); 71 | }); 72 | } 73 | 74 | await tbClient.getOtaPackageService().deleteOtaPackage(otaPackage.id!.id!); 75 | 76 | print( 77 | '**********************************************************************'); 78 | } 79 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 4.0.0 2 | - Changes in TbStorage interface 3 | 4 | ## 3.0.1 5 | 6 | - Adapted to backend changes for version information representation. 7 | - Fixed signup discrepancy. 8 | 9 | ## 3.0.0 10 | 11 | - Introduced a new API for dynamically configuring via mobile center. 12 | - The minimum supported TB version is 3.9.0 and higher. 13 | 14 | ## 2.0.0 15 | 16 | - Enhanced TbStorage interface for improved usability. 17 | - Introduced a new API for alarm activity management, including support for comments and additional functionalities. 18 | 19 | ## 1.3.1 20 | 21 | - Increased the minimum supported ThingsBoard version to 3.8.0. 22 | 23 | ## 1.3.0 24 | 25 | - **New APIs:** 26 | - `/api/alarm/types` - Fetches available alarm types. 27 | - `/api/users/info` - Retrieves user information. 28 | 29 | - **Enhancements:** 30 | - Added the ability to log request and response details for improved debugging. 31 | 32 | - **Bug Fixes:** 33 | - Various minor bug fixes to improve stability and performance. 34 | 35 | ## 1.2.0 36 | 37 | - Introduced the ability to configure access to custom applications using a login with a QR code feature. 38 | - Update API and models according to ThingsBoard platform version 3.7.0 39 | - Fixed the issue with resolving supported platform versions. 40 | - Implemented other minor fixes. 41 | 42 | ## 1.1.1 43 | 44 | - Introduced a NotificationService, which allows you to receive notification data. 45 | 46 | ## 1.1.0 47 | 48 | - Updated the API and models to align with the latest ThingsBoard platform, version 3.6.3 49 | - Introduced support for push notifications 50 | 51 | ## 1.0.9 52 | 53 | - Update API and models according to ThingsBoard platform version 3.6.2 54 | - Fixed issue [#13](https://github.com/thingsboard/dart_thingsboard_client/issues/13): Problem occurred when using web socket and loosing internet 55 | - Fixed issue [#19](https://github.com/thingsboard/dart_thingsboard_client/issues/19): incorrect AlarmDataCmd 56 | - Fixed issue [#21](https://github.com/thingsboard/dart_thingsboard_client/issues/21): incorrect updated notification in subscription 57 | 58 | ## 1.0.8 59 | 60 | - Update API and models according to ThingsBoard platform version 3.6.0 61 | - Fixed issue [#17](https://github.com/thingsboard/dart_thingsboard_client/issues/17): get json attributes when value is array 62 | 63 | ## 1.0.7 64 | 65 | - Fixed incorrect deserializing alarm models 66 | 67 | ## 1.0.6 68 | 69 | - Update API and models according to ThingsBoard platform version 3.5.0 70 | 71 | ## 1.0.5 72 | 73 | - Update API and models according to ThingsBoard platform version 3.4.2 74 | 75 | ## 1.0.4 76 | 77 | - Update API and models according to ThingsBoard platform version 3.4.0 78 | - Added MFA support 79 | - Fix dart analysis issues 80 | 81 | ## 1.0.3 82 | 83 | - Add `terms of use` to self-registration parameters 84 | 85 | ## 1.0.2 86 | 87 | - Add support for web platform 88 | 89 | ## 1.0.1 90 | 91 | - Improve description 92 | - Improve pubspec: add github links 93 | - Use formatting according to dartfmt 94 | 95 | ## 1.0.0 96 | 97 | - Initial version, created by Igor Kulikov 98 | -------------------------------------------------------------------------------- /lib/src/service/notifications_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_pe_client/thingsboard_client.dart'; 2 | 3 | PageData parseNotificationPageData( 4 | Map json) { 5 | return PageData.fromJson(json, (json) => PushNotification.fromJson(json)); 6 | } 7 | 8 | class NotificationsService { 9 | const NotificationsService._internal(this._tbClient); 10 | 11 | factory NotificationsService(ThingsboardClient tbClient) { 12 | return NotificationsService._internal(tbClient); 13 | } 14 | 15 | final ThingsboardClient _tbClient; 16 | 17 | Future> getNotifications( 18 | PushNotificationQuery query, { 19 | RequestConfig? requestConfig, 20 | }) async { 21 | final queryParams = query.toQueryParameters(); 22 | final response = await _tbClient.get>( 23 | '/api/notifications', 24 | queryParameters: queryParams, 25 | options: defaultHttpOptionsFromConfig(requestConfig), 26 | ); 27 | 28 | return _tbClient.compute(parseNotificationPageData, response.data!); 29 | } 30 | 31 | Future markAllNotificationsAsRead( 32 | String deliveryMethod, { 33 | RequestConfig? requestConfig, 34 | }) async { 35 | final response = await _tbClient.put>( 36 | '/api/notifications/read', 37 | queryParameters: {'deliveryMethod': deliveryMethod}, 38 | options: defaultHttpOptionsFromConfig(requestConfig), 39 | ); 40 | 41 | return response.statusCode!; 42 | } 43 | 44 | Future deleteNotification( 45 | String id, { 46 | RequestConfig? requestConfig, 47 | }) async { 48 | final response = await _tbClient.delete( 49 | '/api/notification/$id', 50 | options: defaultHttpOptionsFromConfig(requestConfig), 51 | ); 52 | 53 | return response.statusCode!; 54 | } 55 | 56 | Future markNotificationAsRead( 57 | String id, { 58 | RequestConfig? requestConfig, 59 | }) async { 60 | final response = await _tbClient.put( 61 | '/api/notification/$id/read', 62 | options: defaultHttpOptionsFromConfig(requestConfig), 63 | ); 64 | 65 | return response.statusCode!; 66 | } 67 | 68 | Future getUnreadNotificationsCount( 69 | String deliveryMethod, { 70 | RequestConfig? requestConfig, 71 | }) async { 72 | final response = await _tbClient.get( 73 | '/api/notifications/unread/count', 74 | queryParameters: {'deliveryMethod': deliveryMethod}, 75 | options: defaultHttpOptionsFromConfig(requestConfig), 76 | ); 77 | 78 | return response.data!; 79 | } 80 | 81 | Future getNotificationById( 82 | String id, { 83 | required String deliveryMethod, 84 | RequestConfig? requestConfig, 85 | }) async { 86 | final response = await _tbClient.get>( 87 | 'api/notification/request/$id', 88 | queryParameters: {'deliveryMethod': deliveryMethod}, 89 | options: defaultHttpOptionsFromConfig(requestConfig), 90 | ); 91 | 92 | return PushNotification.fromJson(response.data!); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /lib/src/service/blob_entity_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:dio/dio.dart'; 2 | import '../model/page/page_link.dart'; 3 | import '../http/http_utils.dart'; 4 | import '../model/page/page_data.dart'; 5 | import '../model/blob_entity_models.dart'; 6 | import '../thingsboard_client_base.dart'; 7 | 8 | PageData parseBlobEntityInfoPageData( 9 | Map json) { 10 | return PageData.fromJson(json, (json) => BlobEntityInfo.fromJson(json)); 11 | } 12 | 13 | class BlobEntityService { 14 | final ThingsboardClient _tbClient; 15 | 16 | factory BlobEntityService(ThingsboardClient tbClient) { 17 | return BlobEntityService._internal(tbClient); 18 | } 19 | 20 | BlobEntityService._internal(this._tbClient); 21 | 22 | Future getBlobEntityInfo(String blobEntityInfoId, 23 | {RequestConfig? requestConfig}) async { 24 | return nullIfNotFound( 25 | (RequestConfig requestConfig) async { 26 | var response = await _tbClient.get>( 27 | '/api/blobEntity/info/$blobEntityInfoId', 28 | options: defaultHttpOptionsFromConfig(requestConfig)); 29 | return response.data != null 30 | ? BlobEntityWithCustomerInfo.fromJson(response.data!) 31 | : null; 32 | }, 33 | requestConfig: requestConfig, 34 | ); 35 | } 36 | 37 | Future downloadBlobEntity(String blobEntityId, 38 | {RequestConfig? requestConfig}) async { 39 | return nullIfNotFound( 40 | (RequestConfig requestConfig) async { 41 | var options = defaultHttpOptionsFromConfig(requestConfig); 42 | options.responseType = ResponseType.stream; 43 | var response = await _tbClient.get( 44 | '/api/blobEntity/$blobEntityId/download', 45 | options: options); 46 | return response.data; 47 | }, 48 | requestConfig: requestConfig, 49 | ); 50 | } 51 | 52 | Future deleteBlobEntity(String blobEntityId, 53 | {RequestConfig? requestConfig}) async { 54 | await _tbClient.delete('/api/blobEntity/$blobEntityId', 55 | options: defaultHttpOptionsFromConfig(requestConfig)); 56 | } 57 | 58 | Future> getBlobEntities(TimePageLink timePageLink, 59 | {String type = '', RequestConfig? requestConfig}) async { 60 | var queryParams = timePageLink.toQueryParameters(); 61 | queryParams['type'] = type; 62 | var response = await _tbClient.get>( 63 | '/api/blobEntities', 64 | queryParameters: queryParams, 65 | options: defaultHttpOptionsFromConfig(requestConfig)); 66 | return _tbClient.compute(parseBlobEntityInfoPageData, response.data!); 67 | } 68 | 69 | Future> getBlobEntitiesByIds(List blobEntityIds, 70 | {RequestConfig? requestConfig}) async { 71 | var response = await _tbClient.get>('/api/blobEntities', 72 | queryParameters: {'blobEntityIds': blobEntityIds.join(',')}, 73 | options: defaultHttpOptionsFromConfig(requestConfig)); 74 | return response.data!.map((e) => BlobEntityInfo.fromJson(e)).toList(); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /lib/src/model/custom_menu_models.dart: -------------------------------------------------------------------------------- 1 | class CustomMenuItem { 2 | String name; 3 | String? iconUrl; 4 | String? materialIcon; 5 | String? iframeUrl; 6 | String? dashboardId; 7 | bool? hideDashboardToolbar; 8 | bool? setAccessToken; 9 | List? childMenuItems; 10 | 11 | CustomMenuItem(this.name, 12 | {this.iconUrl, 13 | this.materialIcon, 14 | this.iframeUrl, 15 | this.dashboardId, 16 | this.hideDashboardToolbar, 17 | this.setAccessToken, 18 | this.childMenuItems}); 19 | 20 | CustomMenuItem.fromJson(Map json) 21 | : name = json['name'], 22 | iconUrl = json['iconUrl'], 23 | materialIcon = json['materialIcon'], 24 | iframeUrl = json['iframeUrl'], 25 | dashboardId = json['dashboardId'], 26 | hideDashboardToolbar = json['hideDashboardToolbar'], 27 | setAccessToken = json['setAccessToken'], 28 | childMenuItems = json['childMenuItems'] != null 29 | ? (json['childMenuItems'] as List) 30 | .map((e) => CustomMenuItem.fromJson(e)) 31 | .toList() 32 | : null; 33 | 34 | Map toJson() { 35 | var json = {'name': name}; 36 | if (iconUrl != null) { 37 | json['iconUrl'] = iconUrl; 38 | } 39 | if (materialIcon != null) { 40 | json['materialIcon'] = materialIcon; 41 | } 42 | if (iframeUrl != null) { 43 | json['iframeUrl'] = iframeUrl; 44 | } 45 | if (dashboardId != null) { 46 | json['dashboardId'] = dashboardId; 47 | } 48 | if (hideDashboardToolbar != null) { 49 | json['hideDashboardToolbar'] = hideDashboardToolbar; 50 | } 51 | if (setAccessToken != null) { 52 | json['setAccessToken'] = setAccessToken; 53 | } 54 | if (childMenuItems != null) { 55 | json['childMenuItems'] = childMenuItems!.map((e) => e.toJson()).toList(); 56 | } 57 | return json; 58 | } 59 | 60 | @override 61 | String toString() { 62 | return 'CustomMenuItem{name: $name, iconUrl: $iconUrl, materialIcon: $materialIcon, iframeUrl: $iframeUrl, dashboardId: $dashboardId, hideDashboardToolbar: $hideDashboardToolbar, setAccessToken: $setAccessToken, childMenuItems: $childMenuItems}'; 63 | } 64 | } 65 | 66 | class CustomMenu { 67 | List? disabledMenuItems; 68 | List? menuItems; 69 | 70 | CustomMenu({this.disabledMenuItems, this.menuItems}); 71 | 72 | CustomMenu.fromJson(Map json) 73 | : disabledMenuItems = json['disabledMenuItems'], 74 | menuItems = json['menuItems'] != null 75 | ? (json['menuItems'] as List) 76 | .map((e) => CustomMenuItem.fromJson(e)) 77 | .toList() 78 | : null; 79 | 80 | Map toJson() { 81 | var json = {}; 82 | if (disabledMenuItems != null) { 83 | json['disabledMenuItems'] = disabledMenuItems; 84 | } 85 | if (menuItems != null) { 86 | json['menuItems'] = menuItems!.map((e) => e.toJson()).toList(); 87 | } 88 | return json; 89 | } 90 | 91 | @override 92 | String toString() { 93 | return 'CustomMenu{disabledMenuItems: $disabledMenuItems, menuItems: $menuItems}'; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /lib/src/error/_thingsboard_error_handler_io.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'dart:io'; 3 | import 'package:dio/dio.dart'; 4 | 5 | import 'thingsboard_error.dart'; 6 | 7 | int httpStatusToThingsboardErrorCode(int status) { 8 | switch (status) { 9 | case HttpStatus.unauthorized: 10 | return ThingsBoardErrorCode.authentication; 11 | case HttpStatus.forbidden: 12 | return ThingsBoardErrorCode.permissionDenied; 13 | case HttpStatus.badRequest: 14 | return ThingsBoardErrorCode.badRequestParams; 15 | case HttpStatus.notFound: 16 | return ThingsBoardErrorCode.itemNotFound; 17 | case HttpStatus.tooManyRequests: 18 | return ThingsBoardErrorCode.tooManyRequests; 19 | case HttpStatus.internalServerError: 20 | return ThingsBoardErrorCode.general; 21 | default: 22 | return ThingsBoardErrorCode.general; 23 | } 24 | } 25 | 26 | ThingsboardError toThingsboardError(error, [StackTrace? stackTrace]) { 27 | ThingsboardError? tbError; 28 | if (error is DioException) { 29 | if (error.response != null && error.response!.data != null) { 30 | var data = error.response!.data; 31 | if (data is ThingsboardError) { 32 | tbError = data; 33 | } else if (data is Map) { 34 | tbError = ThingsboardError.fromJson(data); 35 | } else if (data is String) { 36 | try { 37 | tbError = ThingsboardError.fromJson(jsonDecode(data)); 38 | } catch (_) {} 39 | } 40 | } else if (error.error != null) { 41 | if (error.error is ThingsboardError) { 42 | tbError = error.error as ThingsboardError; 43 | } else if (error.error is SocketException) { 44 | tbError = ThingsboardError( 45 | error: error, 46 | message: 'Unable to connect', 47 | errorCode: ThingsBoardErrorCode.general); 48 | } else { 49 | tbError = ThingsboardError( 50 | error: error, 51 | message: error.error.toString(), 52 | errorCode: ThingsBoardErrorCode.general); 53 | } 54 | } 55 | if (tbError == null && 56 | error.response != null && 57 | error.response!.statusCode != null) { 58 | var httpStatus = error.response!.statusCode!; 59 | var message = (httpStatus.toString() + 60 | ': ' + 61 | (error.response!.statusMessage != null 62 | ? error.response!.statusMessage! 63 | : 'Unknown')); 64 | tbError = ThingsboardError( 65 | error: error, 66 | message: message, 67 | errorCode: httpStatusToThingsboardErrorCode(httpStatus), 68 | status: httpStatus); 69 | } 70 | } else if (error is ThingsboardError) { 71 | tbError = error; 72 | } 73 | if (tbError != null && tbError.errorCode == null && tbError.status != null) { 74 | tbError.errorCode = httpStatusToThingsboardErrorCode(tbError.status!); 75 | } 76 | tbError ??= ThingsboardError( 77 | error: error, 78 | message: error.toString(), 79 | errorCode: ThingsBoardErrorCode.general); 80 | 81 | StackTrace? errorStackTrace; 82 | if (tbError.error is Error) { 83 | errorStackTrace = tbError.error.stackTrace; 84 | } 85 | 86 | tbError.stackTrace = stackTrace ?? 87 | tbError.getStackTrace() ?? 88 | errorStackTrace ?? 89 | StackTrace.current; 90 | 91 | return tbError; 92 | } 93 | -------------------------------------------------------------------------------- /lib/src/error/_thingsboard_error_handler_html.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'dart:html'; 3 | import 'package:dio/dio.dart'; 4 | 5 | import 'thingsboard_error.dart'; 6 | 7 | int httpStatusToThingsboardErrorCode(int status) { 8 | switch (status) { 9 | case HttpStatus.unauthorized: 10 | return ThingsBoardErrorCode.authentication; 11 | case HttpStatus.forbidden: 12 | return ThingsBoardErrorCode.permissionDenied; 13 | case HttpStatus.badRequest: 14 | return ThingsBoardErrorCode.badRequestParams; 15 | case HttpStatus.notFound: 16 | return ThingsBoardErrorCode.itemNotFound; 17 | case HttpStatus.tooManyRequests: 18 | return ThingsBoardErrorCode.tooManyRequests; 19 | case HttpStatus.internalServerError: 20 | return ThingsBoardErrorCode.general; 21 | default: 22 | return ThingsBoardErrorCode.general; 23 | } 24 | } 25 | 26 | ThingsboardError toThingsboardError(error, [StackTrace? stackTrace]) { 27 | ThingsboardError? tbError; 28 | if (error is DioException) { 29 | if (error.response != null && error.response!.data != null) { 30 | var data = error.response!.data; 31 | if (data is ThingsboardError) { 32 | tbError = data; 33 | } else if (data is Map) { 34 | tbError = ThingsboardError.fromJson(data); 35 | } else if (data is String) { 36 | try { 37 | tbError = ThingsboardError.fromJson(jsonDecode(data)); 38 | } catch (_) {} 39 | } 40 | } else if (error.error != null) { 41 | if (error.error is ThingsboardError) { 42 | tbError = error.error as ThingsboardError; 43 | } /* else if (error.error is SocketException) { 44 | tbError = ThingsboardError( 45 | error: error, 46 | message: 'Unable to connect', 47 | errorCode: ThingsBoardErrorCode.general); 48 | }*/ 49 | else { 50 | tbError = ThingsboardError( 51 | error: error, 52 | message: error.error.toString(), 53 | errorCode: ThingsBoardErrorCode.general); 54 | } 55 | } 56 | if (tbError == null && 57 | error.response != null && 58 | error.response!.statusCode != null) { 59 | var httpStatus = error.response!.statusCode!; 60 | var message = (httpStatus.toString() + 61 | ': ' + 62 | (error.response!.statusMessage != null 63 | ? error.response!.statusMessage! 64 | : 'Unknown')); 65 | tbError = ThingsboardError( 66 | error: error, 67 | message: message, 68 | errorCode: httpStatusToThingsboardErrorCode(httpStatus), 69 | status: httpStatus); 70 | } 71 | } else if (error is ThingsboardError) { 72 | tbError = error; 73 | } 74 | if (tbError != null && tbError.errorCode == null && tbError.status != null) { 75 | tbError.errorCode = httpStatusToThingsboardErrorCode(tbError.status!); 76 | } 77 | tbError ??= ThingsboardError( 78 | error: error, 79 | message: error.toString(), 80 | errorCode: ThingsBoardErrorCode.general); 81 | 82 | StackTrace? errorStackTrace; 83 | if (tbError.error is Error) { 84 | errorStackTrace = tbError.error.stackTrace; 85 | } 86 | 87 | tbError.stackTrace = stackTrace ?? 88 | tbError.getStackTrace() ?? 89 | errorStackTrace ?? 90 | StackTrace.current; 91 | 92 | return tbError; 93 | } 94 | -------------------------------------------------------------------------------- /lib/src/service/resource_service.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:dio/dio.dart'; 4 | 5 | import '../thingsboard_client_base.dart'; 6 | import '../http/http_utils.dart'; 7 | import '../model/model.dart'; 8 | 9 | PageData parseResourceInfoPageData(Map json) { 10 | return PageData.fromJson(json, (json) => TbResourceInfo.fromJson(json)); 11 | } 12 | 13 | class ResourceService { 14 | final ThingsboardClient _tbClient; 15 | 16 | factory ResourceService(ThingsboardClient tbClient) { 17 | return ResourceService._internal(tbClient); 18 | } 19 | 20 | ResourceService._internal(this._tbClient); 21 | 22 | Future downloadResource(String resourceId, 23 | {RequestConfig? requestConfig}) async { 24 | return nullIfNotFound( 25 | (RequestConfig requestConfig) async { 26 | var options = defaultHttpOptionsFromConfig(requestConfig); 27 | options.responseType = ResponseType.stream; 28 | var response = await _tbClient.get( 29 | '/api/resource/$resourceId/download', 30 | options: options); 31 | return response.data; 32 | }, 33 | requestConfig: requestConfig, 34 | ); 35 | } 36 | 37 | Future getResource(String resourceId, 38 | {RequestConfig? requestConfig}) async { 39 | return nullIfNotFound( 40 | (RequestConfig requestConfig) async { 41 | var response = await _tbClient.get>( 42 | '/api/resource/$resourceId', 43 | options: defaultHttpOptionsFromConfig(requestConfig)); 44 | return response.data != null 45 | ? TbResource.fromJson(response.data!) 46 | : null; 47 | }, 48 | requestConfig: requestConfig, 49 | ); 50 | } 51 | 52 | Future getResourceInfo(String resourceId, 53 | {RequestConfig? requestConfig}) async { 54 | return nullIfNotFound( 55 | (RequestConfig requestConfig) async { 56 | var response = await _tbClient.get>( 57 | '/api/resource/info/$resourceId', 58 | options: defaultHttpOptionsFromConfig(requestConfig)); 59 | return response.data != null 60 | ? TbResourceInfo.fromJson(response.data!) 61 | : null; 62 | }, 63 | requestConfig: requestConfig, 64 | ); 65 | } 66 | 67 | Future saveResource(TbResource resource, 68 | {RequestConfig? requestConfig}) async { 69 | var response = await _tbClient.post>('/api/resource', 70 | data: jsonEncode(resource), 71 | options: defaultHttpOptionsFromConfig(requestConfig)); 72 | return TbResource.fromJson(response.data!); 73 | } 74 | 75 | Future deleteResource(String resourceId, 76 | {RequestConfig? requestConfig}) async { 77 | await _tbClient.delete('/api/resource/$resourceId', 78 | options: defaultHttpOptionsFromConfig(requestConfig)); 79 | } 80 | 81 | Future> getResources(PageLink pageLink, 82 | {RequestConfig? requestConfig}) async { 83 | var response = await _tbClient.get>('/api/resource', 84 | queryParameters: pageLink.toQueryParameters(), 85 | options: defaultHttpOptionsFromConfig(requestConfig)); 86 | return _tbClient.compute(parseResourceInfoPageData, response.data!); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /lib/src/service/self_register_service.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:dio/dio.dart'; 4 | 5 | import '../http/http_utils.dart'; 6 | import '../model/mobile/mobile_info_query.dart'; 7 | import '../model/self_register_models.dart'; 8 | import '../thingsboard_client_base.dart'; 9 | 10 | class SelfRegistrationService { 11 | final ThingsboardClient _tbClient; 12 | 13 | factory SelfRegistrationService(ThingsboardClient tbClient) { 14 | return SelfRegistrationService._internal(tbClient); 15 | } 16 | 17 | SelfRegistrationService._internal(this._tbClient); 18 | 19 | Future getSelfRegistrationParams( 20 | {RequestConfig? requestConfig}) async { 21 | return nullIfNotFound( 22 | (RequestConfig requestConfig) async { 23 | var response = await _tbClient.get>( 24 | '/api/selfRegistration/selfRegistrationParams', 25 | options: defaultHttpOptionsFromConfig(requestConfig)); 26 | return response.data != null 27 | ? SelfRegistrationParams.fromJson(response.data!) 28 | : null; 29 | }, 30 | requestConfig: requestConfig, 31 | ); 32 | } 33 | 34 | Future saveSelfRegistrationParams( 35 | SelfRegistrationParams selfRegistrationParams, 36 | {RequestConfig? requestConfig}) async { 37 | var response = await _tbClient.post>( 38 | '/api/selfRegistration/selfRegistrationParams', 39 | data: jsonEncode(selfRegistrationParams), 40 | options: defaultHttpOptionsFromConfig(requestConfig)); 41 | return SelfRegistrationParams.fromJson(response.data!); 42 | } 43 | 44 | Future getSignUpSelfRegistrationParams( 45 | {String? pkgName, RequestConfig? requestConfig}) async { 46 | return nullIfNotFound( 47 | (RequestConfig requestConfig) async { 48 | var queryParams = {}; 49 | if (pkgName != null) { 50 | queryParams['pkgName'] = pkgName; 51 | } 52 | var response = await _tbClient.get>( 53 | '/api/noauth/selfRegistration/signUpSelfRegistrationParams', 54 | queryParameters: queryParams, 55 | options: defaultHttpOptionsFromConfig(requestConfig)); 56 | return response.data != null 57 | ? SignUpSelfRegistrationParams.fromJson(response.data!) 58 | : null; 59 | }, 60 | requestConfig: requestConfig, 61 | ); 62 | } 63 | 64 | Future getPrivacyPolicy({ 65 | MobileInfoQuery? query, 66 | RequestConfig? requestConfig, 67 | }) async { 68 | final queryParams = query?.toQueryParameters(); 69 | final options = defaultHttpOptionsFromConfig(requestConfig); 70 | options.responseType = ResponseType.plain; 71 | var response = await _tbClient.get( 72 | '/api/noauth/selfRegistration/privacyPolicy', 73 | options: options, 74 | queryParameters: queryParams, 75 | ); 76 | 77 | return response.data!; 78 | } 79 | 80 | Future getTermsOfUse({ 81 | MobileInfoQuery? query, 82 | RequestConfig? requestConfig, 83 | }) async { 84 | final queryParams = query?.toQueryParameters(); 85 | final options = defaultHttpOptionsFromConfig(requestConfig); 86 | options.responseType = ResponseType.plain; 87 | var response = await _tbClient.get( 88 | '/api/noauth/selfRegistration/termsOfUse', 89 | options: options, 90 | queryParameters: queryParams, 91 | ); 92 | return response.data!; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /lib/src/service/integration_service.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import '../thingsboard_client_base.dart'; 4 | import '../http/http_utils.dart'; 5 | import '../model/model.dart'; 6 | 7 | PageData parseIntegrationPageData(Map json) { 8 | return PageData.fromJson(json, (json) => Integration.fromJson(json)); 9 | } 10 | 11 | class IntegrationService { 12 | final ThingsboardClient _tbClient; 13 | 14 | factory IntegrationService(ThingsboardClient tbClient) { 15 | return IntegrationService._internal(tbClient); 16 | } 17 | 18 | IntegrationService._internal(this._tbClient); 19 | 20 | Future getIntegration(String integrationId, 21 | {RequestConfig? requestConfig}) async { 22 | return nullIfNotFound( 23 | (RequestConfig requestConfig) async { 24 | var response = await _tbClient.get>( 25 | '/api/integration/$integrationId', 26 | options: defaultHttpOptionsFromConfig(requestConfig)); 27 | return response.data != null 28 | ? Integration.fromJson(response.data!) 29 | : null; 30 | }, 31 | requestConfig: requestConfig, 32 | ); 33 | } 34 | 35 | Future getIntegrationByRoutingKey(String routingKey, 36 | {RequestConfig? requestConfig}) async { 37 | return nullIfNotFound( 38 | (RequestConfig requestConfig) async { 39 | var response = await _tbClient.get>( 40 | '/api/integration/routingKey/$routingKey', 41 | options: defaultHttpOptionsFromConfig(requestConfig)); 42 | return response.data != null 43 | ? Integration.fromJson(response.data!) 44 | : null; 45 | }, 46 | requestConfig: requestConfig, 47 | ); 48 | } 49 | 50 | Future saveIntegration(Integration integration, 51 | {RequestConfig? requestConfig}) async { 52 | var response = await _tbClient.post>( 53 | '/api/integration', 54 | data: jsonEncode(integration), 55 | options: defaultHttpOptionsFromConfig(requestConfig)); 56 | return Integration.fromJson(response.data!); 57 | } 58 | 59 | Future deleteIntegration(String integrationId, 60 | {RequestConfig? requestConfig}) async { 61 | await _tbClient.delete('/api/integration/$integrationId', 62 | options: defaultHttpOptionsFromConfig(requestConfig)); 63 | } 64 | 65 | Future checkIntegrationConnection(Integration integration, 66 | {RequestConfig? requestConfig}) async { 67 | await _tbClient.delete('/api/integration/check', 68 | data: jsonEncode(integration), 69 | options: defaultHttpOptionsFromConfig(requestConfig)); 70 | } 71 | 72 | Future> getIntegrations(PageLink pageLink, 73 | {RequestConfig? requestConfig}) async { 74 | var response = await _tbClient.get>( 75 | '/api/integrations', 76 | queryParameters: pageLink.toQueryParameters(), 77 | options: defaultHttpOptionsFromConfig(requestConfig)); 78 | return _tbClient.compute(parseIntegrationPageData, response.data!); 79 | } 80 | 81 | Future> getIntegrationsByIds(List integrationIds, 82 | {RequestConfig? requestConfig}) async { 83 | var response = await _tbClient.get>('/api/integrations', 84 | queryParameters: {'integrationIds': integrationIds.join(',')}, 85 | options: defaultHttpOptionsFromConfig(requestConfig)); 86 | return response.data!.map((e) => Integration.fromJson(e)).toList(); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /lib/src/service/tenant_service.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import '../thingsboard_client_base.dart'; 4 | import '../http/http_utils.dart'; 5 | import '../model/model.dart'; 6 | 7 | PageData parseTenantPageData(Map json) { 8 | return PageData.fromJson(json, (json) => Tenant.fromJson(json)); 9 | } 10 | 11 | PageData parseTenantInfoPageData(Map json) { 12 | return PageData.fromJson(json, (json) => TenantInfo.fromJson(json)); 13 | } 14 | 15 | class TenantService { 16 | final ThingsboardClient _tbClient; 17 | 18 | factory TenantService(ThingsboardClient tbClient) { 19 | return TenantService._internal(tbClient); 20 | } 21 | 22 | TenantService._internal(this._tbClient); 23 | 24 | Future getTenant(String tenantId, 25 | {RequestConfig? requestConfig}) async { 26 | return nullIfNotFound( 27 | (RequestConfig requestConfig) async { 28 | var response = await _tbClient.get>( 29 | '/api/tenant/$tenantId', 30 | options: defaultHttpOptionsFromConfig(requestConfig)); 31 | return response.data != null ? Tenant.fromJson(response.data!) : null; 32 | }, 33 | requestConfig: requestConfig, 34 | ); 35 | } 36 | 37 | Future getTenantInfo(String tenantId, 38 | {RequestConfig? requestConfig}) async { 39 | return nullIfNotFound( 40 | (RequestConfig requestConfig) async { 41 | var response = await _tbClient.get>( 42 | '/api/tenant/info/$tenantId', 43 | options: defaultHttpOptionsFromConfig(requestConfig)); 44 | return response.data != null 45 | ? TenantInfo.fromJson(response.data!) 46 | : null; 47 | }, 48 | requestConfig: requestConfig, 49 | ); 50 | } 51 | 52 | Future saveTenant(Tenant tenant, 53 | {RequestConfig? requestConfig}) async { 54 | var response = await _tbClient.post>('/api/tenant', 55 | data: jsonEncode(tenant), 56 | options: defaultHttpOptionsFromConfig(requestConfig)); 57 | return Tenant.fromJson(response.data!); 58 | } 59 | 60 | Future deleteTenant(String tenantId, 61 | {RequestConfig? requestConfig}) async { 62 | await _tbClient.delete('/api/tenant/$tenantId', 63 | options: defaultHttpOptionsFromConfig(requestConfig)); 64 | } 65 | 66 | Future> getTenants(PageLink pageLink, 67 | {RequestConfig? requestConfig}) async { 68 | var queryParams = pageLink.toQueryParameters(); 69 | var response = await _tbClient.get>('/api/tenants', 70 | queryParameters: queryParams, 71 | options: defaultHttpOptionsFromConfig(requestConfig)); 72 | return _tbClient.compute(parseTenantPageData, response.data!); 73 | } 74 | 75 | Future> getTenantInfos(PageLink pageLink, 76 | {RequestConfig? requestConfig}) async { 77 | var queryParams = pageLink.toQueryParameters(); 78 | var response = await _tbClient.get>('/api/tenantInfos', 79 | queryParameters: queryParams, 80 | options: defaultHttpOptionsFromConfig(requestConfig)); 81 | return _tbClient.compute(parseTenantInfoPageData, response.data!); 82 | } 83 | 84 | Future> getTenantsByIds(List tenantIds, 85 | {RequestConfig? requestConfig}) async { 86 | var response = await _tbClient.get>('/api/tenants', 87 | queryParameters: {'tenantIds': tenantIds.join(',')}, 88 | options: defaultHttpOptionsFromConfig(requestConfig)); 89 | return response.data!.map((e) => Tenant.fromJson(e)).toList(); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /lib/src/service/group_permission_service.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import '../thingsboard_client_base.dart'; 4 | import '../http/http_utils.dart'; 5 | import '../model/model.dart'; 6 | 7 | class GroupPermissionService { 8 | final ThingsboardClient _tbClient; 9 | 10 | factory GroupPermissionService(ThingsboardClient tbClient) { 11 | return GroupPermissionService._internal(tbClient); 12 | } 13 | 14 | GroupPermissionService._internal(this._tbClient); 15 | 16 | Future getGroupPermission(String groupPermissionId, 17 | {RequestConfig? requestConfig}) async { 18 | return nullIfNotFound( 19 | (RequestConfig requestConfig) async { 20 | var response = await _tbClient.get>( 21 | '/api/groupPermission/$groupPermissionId', 22 | options: defaultHttpOptionsFromConfig(requestConfig)); 23 | return response.data != null 24 | ? GroupPermission.fromJson(response.data!) 25 | : null; 26 | }, 27 | requestConfig: requestConfig, 28 | ); 29 | } 30 | 31 | Future getGroupPermissionInfo( 32 | String groupPermissionId, bool isUserGroup, 33 | {RequestConfig? requestConfig}) async { 34 | return nullIfNotFound( 35 | (RequestConfig requestConfig) async { 36 | var response = await _tbClient.get>( 37 | '/api/groupPermission/info/$groupPermissionId', 38 | queryParameters: {'isUserGroup': isUserGroup}, 39 | options: defaultHttpOptionsFromConfig(requestConfig)); 40 | return response.data != null 41 | ? GroupPermissionInfo.fromJson(response.data!) 42 | : null; 43 | }, 44 | requestConfig: requestConfig, 45 | ); 46 | } 47 | 48 | Future saveGroupPermission(GroupPermission groupPermission, 49 | {RequestConfig? requestConfig}) async { 50 | var response = await _tbClient.post>( 51 | '/api/groupPermission', 52 | data: jsonEncode(groupPermission), 53 | options: defaultHttpOptionsFromConfig(requestConfig)); 54 | return GroupPermission.fromJson(response.data!); 55 | } 56 | 57 | Future deleteGroupPermission(String groupPermissionId, 58 | {RequestConfig? requestConfig}) async { 59 | await _tbClient.delete('/api/groupPermission/$groupPermissionId', 60 | options: defaultHttpOptionsFromConfig(requestConfig)); 61 | } 62 | 63 | Future> getUserGroupPermissions(String userGroupId, 64 | {RequestConfig? requestConfig}) async { 65 | var response = await _tbClient.get>( 66 | '/api/userGroup/$userGroupId/groupPermissions', 67 | options: defaultHttpOptionsFromConfig(requestConfig)); 68 | return response.data!.map((e) => GroupPermissionInfo.fromJson(e)).toList(); 69 | } 70 | 71 | Future> loadUserGroupPermissionInfos( 72 | List permissions, 73 | {RequestConfig? requestConfig}) async { 74 | var response = await _tbClient.post>( 75 | '/api/userGroup/groupPermissions/info', 76 | data: jsonEncode(permissions), 77 | options: defaultHttpOptionsFromConfig(requestConfig)); 78 | return response.data!.map((e) => GroupPermissionInfo.fromJson(e)).toList(); 79 | } 80 | 81 | Future> getEntityGroupPermissions( 82 | String entityGroupId, 83 | {RequestConfig? requestConfig}) async { 84 | var response = await _tbClient.get>( 85 | '/api/entityGroup/$entityGroupId/groupPermissions', 86 | options: defaultHttpOptionsFromConfig(requestConfig)); 87 | return response.data!.map((e) => GroupPermissionInfo.fromJson(e)).toList(); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /lib/src/model/customer_models.dart: -------------------------------------------------------------------------------- 1 | import 'entity_type_models.dart'; 2 | import 'group_entity.dart'; 3 | import 'exportable_entity.dart'; 4 | import 'id/customer_id.dart'; 5 | import 'id/entity_id.dart'; 6 | import 'id/has_uuid.dart'; 7 | import 'id/tenant_id.dart'; 8 | import 'contact_based_model.dart'; 9 | 10 | class Customer extends ContactBased 11 | with ExportableEntity 12 | implements GroupEntity { 13 | TenantId? tenantId; 14 | CustomerId? parentCustomerId; 15 | String title; 16 | CustomerId? externalId; 17 | 18 | Customer(this.title); 19 | 20 | Customer.fromJson(Map json) 21 | : tenantId = TenantId.fromJson(json['tenantId']), 22 | parentCustomerId = json['parentCustomerId'] != null 23 | ? CustomerId.fromJson(json['parentCustomerId']) 24 | : null, 25 | title = json['title'], 26 | externalId = json['externalId'] != null 27 | ? CustomerId.fromJson(json['externalId']) 28 | : null, 29 | super.fromJson(json); 30 | 31 | @override 32 | Map toJson() { 33 | var json = super.toJson(); 34 | if (tenantId != null) { 35 | json['tenantId'] = tenantId!.toJson(); 36 | } 37 | if (parentCustomerId != null) { 38 | json['parentCustomerId'] = parentCustomerId!.toJson(); 39 | } 40 | json['title'] = title; 41 | if (externalId != null) { 42 | json['externalId'] = externalId!.toJson(); 43 | } 44 | return json; 45 | } 46 | 47 | @override 48 | String getName() { 49 | return title; 50 | } 51 | 52 | @override 53 | TenantId? getTenantId() { 54 | return tenantId; 55 | } 56 | 57 | @override 58 | void setTenantId(TenantId? tenantId) { 59 | this.tenantId = tenantId; 60 | } 61 | 62 | @override 63 | CustomerId? getCustomerId() { 64 | return parentCustomerId; 65 | } 66 | 67 | @override 68 | EntityType getEntityType() { 69 | return EntityType.CUSTOMER; 70 | } 71 | 72 | @override 73 | EntityId? getOwnerId() { 74 | return parentCustomerId != null && !parentCustomerId!.isNullUid() 75 | ? parentCustomerId 76 | : tenantId; 77 | } 78 | 79 | @override 80 | void setOwnerId(EntityId entityId) { 81 | if (entityId.entityType == EntityType.CUSTOMER) { 82 | parentCustomerId = CustomerId(entityId.id!); 83 | } else { 84 | parentCustomerId = CustomerId(nullUuid); 85 | } 86 | } 87 | 88 | bool isSubCustomer() => 89 | parentCustomerId != null && !parentCustomerId!.isNullUid(); 90 | 91 | @override 92 | String toString() { 93 | return 'Customer{${contactBasedString('tenantId: $tenantId, parentCustomerId: $parentCustomerId, title: $title, externalId: $externalId')}}'; 94 | } 95 | 96 | @override 97 | CustomerId? getExternalId() { 98 | return externalId; 99 | } 100 | 101 | @override 102 | void setExternalId(CustomerId? externalId) { 103 | this.externalId = externalId; 104 | } 105 | } 106 | 107 | class ShortCustomerInfo { 108 | CustomerId customerId; 109 | String title; 110 | bool isPublic; 111 | 112 | ShortCustomerInfo.fromJson(Map json) 113 | : customerId = CustomerId.fromJson(json['customerId']), 114 | title = json['title'], 115 | isPublic = json['isPublic'] ?? false; 116 | 117 | Map toJson() { 118 | var json = { 119 | 'customerId': customerId.toJson(), 120 | 'title': title, 121 | 'isPublic': isPublic 122 | }; 123 | return json; 124 | } 125 | 126 | @override 127 | String toString() { 128 | return 'ShortCustomerInfo{customerId: $customerId, title: $title, isPublic: $isPublic}'; 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /example/entity_group.dart: -------------------------------------------------------------------------------- 1 | import 'package:thingsboard_pe_client/thingsboard_client.dart'; 2 | 3 | const thingsBoardApiEndpoint = 'http://localhost:8080'; 4 | const username = 'tenant@thingsboard.org'; 5 | const password = 'tenant'; 6 | 7 | late ThingsboardClient tbClient; 8 | 9 | void main() async { 10 | try { 11 | tbClient = ThingsboardClient(thingsBoardApiEndpoint); 12 | 13 | await tbClient.login(LoginRequest(username, password)); 14 | 15 | await fetchEntityGroupsExample(); 16 | await fetchEntityGroupEntitiesExample(); 17 | await getOwnersExample(); 18 | 19 | await tbClient.logout( 20 | requestConfig: RequestConfig(ignoreLoading: true, ignoreErrors: true)); 21 | } catch (e, s) { 22 | print('Error: $e'); 23 | print('Stack: $s'); 24 | } 25 | } 26 | 27 | Future fetchEntityGroupsExample() async { 28 | print( 29 | '**********************************************************************'); 30 | print( 31 | '* FETCH ENTITY GROUPS EXAMPLE *'); 32 | print( 33 | '**********************************************************************'); 34 | 35 | for (var groupType in [ 36 | EntityType.DEVICE, 37 | EntityType.ASSET, 38 | EntityType.ENTITY_VIEW, 39 | EntityType.DASHBOARD, 40 | EntityType.CUSTOMER, 41 | EntityType.USER, 42 | EntityType.EDGE 43 | ]) { 44 | var entityGroups = 45 | await tbClient.getEntityGroupService().getEntityGroupsByType(groupType); 46 | print('found ${groupType.toShortString()} groups: $entityGroups'); 47 | } 48 | 49 | print( 50 | '**********************************************************************'); 51 | } 52 | 53 | Future fetchEntityGroupEntitiesExample() async { 54 | print( 55 | '**********************************************************************'); 56 | print( 57 | '* FETCH ENTITY GROUP ENTITIES EXAMPLE *'); 58 | print( 59 | '**********************************************************************'); 60 | 61 | var deviceGroupAll = await tbClient 62 | .getEntityGroupService() 63 | .getEntityGroupAllByOwnerAndType( 64 | TenantId(tbClient.getAuthUser()!.tenantId), EntityType.DEVICE); 65 | print('found device group all: $deviceGroupAll'); 66 | 67 | var pageLink = PageLink(10); 68 | PageData deviceEntities; 69 | do { 70 | deviceEntities = await tbClient 71 | .getEntityGroupService() 72 | .getEntities(deviceGroupAll!.id!.id!, pageLink); 73 | print('Device group all short entity views: $deviceEntities'); 74 | pageLink = pageLink.nextPageLink(); 75 | } while (deviceEntities.hasNext); 76 | 77 | pageLink = PageLink(10); 78 | PageData devices; 79 | do { 80 | devices = await tbClient 81 | .getDeviceService() 82 | .getDevicesByEntityGroupId(deviceGroupAll.id!.id!, pageLink); 83 | print('Device group all devices: $devices'); 84 | pageLink = pageLink.nextPageLink(); 85 | } while (devices.hasNext); 86 | 87 | print( 88 | '**********************************************************************'); 89 | } 90 | 91 | Future getOwnersExample() async { 92 | print( 93 | '**********************************************************************'); 94 | print( 95 | '* GET OWNERS EXAMPLE *'); 96 | print( 97 | '**********************************************************************'); 98 | 99 | var pageLink = PageLink(10); 100 | PageData owners; 101 | do { 102 | owners = await tbClient.getEntityGroupService().getOwners(pageLink); 103 | print('owners: $owners'); 104 | pageLink = pageLink.nextPageLink(); 105 | } while (owners.hasNext); 106 | print( 107 | '**********************************************************************'); 108 | 109 | print( 110 | '**********************************************************************'); 111 | } 112 | -------------------------------------------------------------------------------- /lib/src/service/signup_service.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:dio/dio.dart'; 4 | import 'package:thingsboard_pe_client/src/model/model.dart'; 5 | 6 | import '../http/http_utils.dart'; 7 | import '../thingsboard_client_base.dart'; 8 | 9 | class SignupService { 10 | final ThingsboardClient _tbClient; 11 | 12 | factory SignupService(ThingsboardClient tbClient) { 13 | return SignupService._internal(tbClient); 14 | } 15 | 16 | SignupService._internal(this._tbClient); 17 | 18 | Future signup( 19 | SignUpRequest signUpRequest, { 20 | RequestConfig? requestConfig, 21 | }) async { 22 | final options = defaultHttpOptionsFromConfig(requestConfig); 23 | options.responseType = ResponseType.plain; 24 | 25 | final response = await _tbClient.post( 26 | '/api/noauth/signup', 27 | data: signUpRequest.toJson(), 28 | options: options, 29 | ); 30 | 31 | return signUpResultFromString(jsonDecode(response.data!)); 32 | } 33 | 34 | Future acceptPrivacyPolicy( 35 | {RequestConfig? requestConfig}) async { 36 | return nullIfNotFound( 37 | (RequestConfig requestConfig) async { 38 | var response = await _tbClient.post>( 39 | '/api/signup/acceptPrivacyPolicy', 40 | options: defaultHttpOptionsFromConfig(requestConfig)); 41 | return response.data != null 42 | ? LoginResponse.fromJson(response.data!) 43 | : null; 44 | }, 45 | requestConfig: requestConfig, 46 | ); 47 | } 48 | 49 | Future privacyPolicyAccepted({RequestConfig? requestConfig}) async { 50 | var response = await _tbClient.get( 51 | '/api/signup/privacyPolicyAccepted', 52 | options: defaultHttpOptionsFromConfig(requestConfig)); 53 | return response.data!; 54 | } 55 | 56 | Future resendEmailActivation( 57 | String email, { 58 | String? pkgName, 59 | PlatformType? platform, 60 | RequestConfig? requestConfig, 61 | }) async { 62 | final queryParams = {'email': email}; 63 | if (pkgName != null) { 64 | queryParams['pkgName'] = pkgName; 65 | queryParams['platform'] = platform?.toShortString(); 66 | } 67 | 68 | await _tbClient.post( 69 | '/api/noauth/resendEmailActivation', 70 | queryParameters: queryParams, 71 | options: defaultHttpOptionsFromConfig(requestConfig), 72 | ); 73 | } 74 | 75 | Future> activateEmail(String emailCode, 76 | {String? pkgName, RequestConfig? requestConfig}) async { 77 | var queryParams = {'emailCode': emailCode}; 78 | if (pkgName != null) { 79 | queryParams['pkgName'] = pkgName; 80 | } 81 | var options = defaultHttpOptionsFromConfig(requestConfig); 82 | options.responseType = ResponseType.plain; 83 | var response = await _tbClient.get('/api/noauth/activateEmail', 84 | queryParameters: queryParams, options: options); 85 | return response; 86 | } 87 | 88 | Future activateUserByEmailCode( 89 | String emailCode, { 90 | String? pkgName, 91 | PlatformType? platform, 92 | RequestConfig? requestConfig, 93 | }) async { 94 | return nullIfNotFound( 95 | (RequestConfig requestConfig) async { 96 | var queryParams = {'emailCode': emailCode}; 97 | if (pkgName != null) { 98 | queryParams['pkgName'] = pkgName; 99 | queryParams['platform'] = platform?.toShortString(); 100 | } 101 | var response = await _tbClient.post>( 102 | '/api/noauth/activateByEmailCode', 103 | queryParameters: queryParams, 104 | options: defaultHttpOptionsFromConfig(requestConfig)); 105 | return response.data != null 106 | ? LoginResponse.fromJson(response.data!) 107 | : null; 108 | }, 109 | requestConfig: requestConfig, 110 | ); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /lib/src/service/converter_service.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import '../model/page/page_link.dart'; 4 | import '../http/http_utils.dart'; 5 | import '../thingsboard_client_base.dart'; 6 | import '../model/converter_models.dart'; 7 | import '../model/page/page_data.dart'; 8 | 9 | PageData parseConverterPageData(Map json) { 10 | return PageData.fromJson(json, (json) => Converter.fromJson(json)); 11 | } 12 | 13 | class ConverterService { 14 | final ThingsboardClient _tbClient; 15 | 16 | factory ConverterService(ThingsboardClient tbClient) { 17 | return ConverterService._internal(tbClient); 18 | } 19 | 20 | ConverterService._internal(this._tbClient); 21 | 22 | Future getConverter(String converterId, 23 | {RequestConfig? requestConfig}) async { 24 | return nullIfNotFound( 25 | (RequestConfig requestConfig) async { 26 | var response = await _tbClient.get>( 27 | '/api/converter/$converterId', 28 | options: defaultHttpOptionsFromConfig(requestConfig)); 29 | return response.data != null 30 | ? Converter.fromJson(response.data!) 31 | : null; 32 | }, 33 | requestConfig: requestConfig, 34 | ); 35 | } 36 | 37 | Future saveConverter(Converter converter, 38 | {RequestConfig? requestConfig}) async { 39 | var response = await _tbClient.post>('/api/converter', 40 | data: jsonEncode(converter), 41 | options: defaultHttpOptionsFromConfig(requestConfig)); 42 | return Converter.fromJson(response.data!); 43 | } 44 | 45 | Future> getConverters(PageLink pageLink, 46 | {RequestConfig? requestConfig}) async { 47 | var response = await _tbClient.get>('/api/converters', 48 | queryParameters: pageLink.toQueryParameters(), 49 | options: defaultHttpOptionsFromConfig(requestConfig)); 50 | return _tbClient.compute(parseConverterPageData, response.data!); 51 | } 52 | 53 | Future deleteConverter(String converterId, 54 | {RequestConfig? requestConfig}) async { 55 | await _tbClient.delete('/api/converter/$converterId', 56 | options: defaultHttpOptionsFromConfig(requestConfig)); 57 | } 58 | 59 | Future> getConvertersByIds(List converterIds, 60 | {RequestConfig? requestConfig}) async { 61 | var response = await _tbClient.get>('/api/converters', 62 | queryParameters: {'converterIds': converterIds.join(',')}, 63 | options: defaultHttpOptionsFromConfig(requestConfig)); 64 | return response.data!.map((e) => Converter.fromJson(e)).toList(); 65 | } 66 | 67 | Future testUpLink(TestUpLinkInputParams inputParams, 68 | {RequestConfig? requestConfig}) async { 69 | var response = await _tbClient.post>( 70 | '/api/converter/testUpLink', 71 | data: jsonEncode(inputParams), 72 | options: defaultHttpOptionsFromConfig(requestConfig)); 73 | return TestConverterResult.fromJson(response.data!); 74 | } 75 | 76 | Future testDownLink(TestDownLinkInputParams inputParams, 77 | {RequestConfig? requestConfig}) async { 78 | var response = await _tbClient.post>( 79 | '/api/converter/testDownLink', 80 | data: jsonEncode(inputParams), 81 | options: defaultHttpOptionsFromConfig(requestConfig)); 82 | return TestConverterResult.fromJson(response.data!); 83 | } 84 | 85 | Future getLatestConverterDebugInput(String converterId, 86 | {RequestConfig? requestConfig}) async { 87 | return nullIfNotFound( 88 | (RequestConfig requestConfig) async { 89 | var response = await _tbClient.get>( 90 | '/api/converter/$converterId/debugIn', 91 | options: defaultHttpOptionsFromConfig(requestConfig)); 92 | return response.data != null 93 | ? ConverterDebugInput.fromJson(response.data!) 94 | : null; 95 | }, 96 | requestConfig: requestConfig, 97 | ); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /lib/src/service/oauth2_service.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:dio/dio.dart'; 4 | import 'package:thingsboard_pe_client/src/error/thingsboard_error.dart'; 5 | 6 | import '../http/http_utils.dart'; 7 | import '../model/model.dart'; 8 | import '../thingsboard_client_base.dart'; 9 | 10 | List parseOauth2ClientRegistrationTemplates( 11 | List json) { 12 | return json.map((e) => OAuth2ClientRegistrationTemplate.fromJson(e)).toList(); 13 | } 14 | 15 | class OAuth2Service { 16 | final ThingsboardClient _tbClient; 17 | 18 | factory OAuth2Service(ThingsboardClient tbClient) { 19 | return OAuth2Service._internal(tbClient); 20 | } 21 | 22 | OAuth2Service._internal(this._tbClient); 23 | 24 | Future> getOAuth2Clients( 25 | {String? pkgName, 26 | PlatformType? platform, 27 | RequestConfig? requestConfig}) async { 28 | var queryParams = {}; 29 | if (pkgName != null) { 30 | queryParams['pkgName'] = pkgName; 31 | } 32 | if (platform != null) { 33 | queryParams['platform'] = platform.toShortString(); 34 | } 35 | 36 | Response> response; 37 | try { 38 | response = await _tbClient.post>( 39 | '/api/noauth/oauth2Clients', 40 | queryParameters: queryParams, 41 | options: defaultHttpOptionsFromConfig(requestConfig)); 42 | } on ThingsboardError catch (e) { 43 | print('dio response $e'); 44 | if (e.status == 302) { 45 | final redirectUrl = e.error.response.headers['location'].first; 46 | response = await _tbClient.post(redirectUrl); 47 | } else { 48 | rethrow; 49 | } 50 | } 51 | 52 | return response.data!.map((e) => OAuth2ClientInfo.fromJson(e)).toList(); 53 | } 54 | 55 | Future saveClientRegistrationTemplate( 56 | OAuth2ClientRegistrationTemplate clientRegistrationTemplate, 57 | {RequestConfig? requestConfig}) async { 58 | var response = await _tbClient.post>( 59 | '/api/oauth2/config/template', 60 | data: jsonEncode(clientRegistrationTemplate), 61 | options: defaultHttpOptionsFromConfig(requestConfig)); 62 | return OAuth2ClientRegistrationTemplate.fromJson(response.data!); 63 | } 64 | 65 | Future deleteClientRegistrationTemplate( 66 | String oAuth2ClientRegistrationTemplateId, 67 | {RequestConfig? requestConfig}) async { 68 | await _tbClient.delete( 69 | '/api/oauth2/config/template/$oAuth2ClientRegistrationTemplateId', 70 | options: defaultHttpOptionsFromConfig(requestConfig)); 71 | } 72 | 73 | Future> getClientRegistrationTemplates( 74 | {RequestConfig? requestConfig}) async { 75 | var response = await _tbClient.get>( 76 | '/api/oauth2/config/template', 77 | options: defaultHttpOptionsFromConfig(requestConfig)); 78 | return _tbClient.compute( 79 | parseOauth2ClientRegistrationTemplates, response.data!); 80 | } 81 | 82 | Future getCurrentOAuth2Info( 83 | {RequestConfig? requestConfig}) async { 84 | var response = await _tbClient.get>( 85 | '/api/oauth2/config', 86 | options: defaultHttpOptionsFromConfig(requestConfig)); 87 | return OAuth2Info.fromJson(response.data!); 88 | } 89 | 90 | Future saveOAuth2Info(OAuth2Info oAuth2Info, 91 | {RequestConfig? requestConfig}) async { 92 | var response = await _tbClient.post>( 93 | '/api/oauth2/config', 94 | data: jsonEncode(oAuth2Info), 95 | options: defaultHttpOptionsFromConfig(requestConfig)); 96 | return OAuth2Info.fromJson(response.data!); 97 | } 98 | 99 | Future getLoginProcessingUrl({RequestConfig? requestConfig}) async { 100 | var options = defaultHttpOptionsFromConfig(requestConfig); 101 | options.responseType = ResponseType.plain; 102 | var response = await _tbClient.get('/api/oauth2/loginProcessingUrl', 103 | options: options); 104 | return response.data!; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /lib/src/model/audit_log_models.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'dart:math'; 3 | 4 | import 'id/audit_log_id.dart'; 5 | import 'id/customer_id.dart'; 6 | import 'id/entity_id.dart'; 7 | 8 | import 'base_data.dart'; 9 | import 'id/tenant_id.dart'; 10 | import 'id/user_id.dart'; 11 | 12 | enum ActionType { 13 | ADDED, 14 | DELETED, 15 | UPDATED, 16 | ATTRIBUTES_UPDATED, 17 | ATTRIBUTES_DELETED, 18 | RPC_CALL, 19 | CREDENTIALS_UPDATED, 20 | ASSIGNED_TO_CUSTOMER, 21 | UNASSIGNED_FROM_CUSTOMER, 22 | ACTIVATED, 23 | SUSPENDED, 24 | CREDENTIALS_READ, 25 | ATTRIBUTES_READ, 26 | ADDED_TO_ENTITY_GROUP, 27 | REMOVED_FROM_ENTITY_GROUP, 28 | RELATION_ADD_OR_UPDATE, 29 | RELATION_DELETED, 30 | RELATIONS_DELETED, 31 | ALARM_ACK, 32 | ALARM_CLEAR, 33 | ALARM_DELETE, 34 | ALARM_ASSIGNED, 35 | ALARM_UNASSIGNED, 36 | REST_API_RULE_ENGINE_CALL, 37 | MADE_PUBLIC, 38 | MADE_PRIVATE, 39 | LOGIN, 40 | LOGOUT, 41 | LOCKOUT, 42 | ASSIGNED_FROM_TENANT, 43 | ASSIGNED_TO_TENANT, 44 | PROVISION_SUCCESS, 45 | PROVISION_FAILURE, 46 | TIMESERIES_UPDATED, 47 | TIMESERIES_DELETED, 48 | CHANGE_OWNER, 49 | ASSIGNED_TO_EDGE, 50 | UNASSIGNED_FROM_EDGE, 51 | ADDED_COMMENT, 52 | UPDATED_COMMENT, 53 | DELETED_COMMENT, 54 | SMS_SENT 55 | } 56 | 57 | ActionType actionTypeFromString(String value) { 58 | return ActionType.values.firstWhere( 59 | (e) => e.toString().split('.')[1].toUpperCase() == value.toUpperCase()); 60 | } 61 | 62 | extension ActionTypeToString on ActionType { 63 | String toShortString() { 64 | return toString().split('.').last; 65 | } 66 | } 67 | 68 | enum ActionStatus { SUCCESS, FAILURE } 69 | 70 | ActionStatus actionStatusFromString(String value) { 71 | return ActionStatus.values.firstWhere( 72 | (e) => e.toString().split('.')[1].toUpperCase() == value.toUpperCase()); 73 | } 74 | 75 | extension ActionStatusToString on ActionStatus { 76 | String toShortString() { 77 | return toString().split('.').last; 78 | } 79 | } 80 | 81 | class AuditLog extends BaseData { 82 | TenantId tenantId; 83 | CustomerId? customerId; 84 | EntityId entityId; 85 | String? entityName; 86 | UserId userId; 87 | String userName; 88 | ActionType actionType; 89 | Map actionData; 90 | ActionStatus actionStatus; 91 | String? actionFailureDetails; 92 | 93 | AuditLog.fromJson(Map json) 94 | : tenantId = TenantId.fromJson(json['tenantId']), 95 | customerId = json['customerId'] != null 96 | ? CustomerId.fromJson(json['customerId']) 97 | : null, 98 | entityId = EntityId.fromJson(json['entityId']), 99 | entityName = json['entityName'], 100 | userId = UserId.fromJson(json['userId']), 101 | userName = json['userName'], 102 | actionType = actionTypeFromString(json['actionType']), 103 | actionData = json['actionData'], 104 | actionStatus = actionStatusFromString(json['actionStatus']), 105 | actionFailureDetails = json['actionFailureDetails'], 106 | super.fromJson(json, (id) => AuditLogId(id)); 107 | 108 | @override 109 | String toString() { 110 | return 'AuditLog{${baseDataString('tenantId: $tenantId, customerId: $customerId, entityId: $entityId, ' 111 | 'entityName: $entityName, userId: $userId, userName: $userName, actionType: $actionType, ' 112 | 'actionData: ${actionDataToString()}, actionStatus: $actionStatus, actionFailureDetails: ${actionFailureDetailsToString()}')}}'; 113 | } 114 | 115 | String actionDataToString() { 116 | var actionDataStr = jsonEncode(actionData); 117 | if (actionDataStr.length > 50) { 118 | actionDataStr = 119 | actionDataStr.substring(0, min(50, actionDataStr.length)) + '...'; 120 | } 121 | return actionDataStr; 122 | } 123 | 124 | String actionFailureDetailsToString() { 125 | if (actionFailureDetails == null) { 126 | return 'null'; 127 | } 128 | if (actionFailureDetails!.length > 50) { 129 | return actionFailureDetails! 130 | .substring(0, min(50, actionFailureDetails!.length)) + 131 | '...'; 132 | } 133 | return actionFailureDetails!; 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /lib/src/model/widget_models.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | import 'base_data.dart'; 4 | import 'has_tenant_id.dart'; 5 | import 'id/tenant_id.dart'; 6 | import 'id/widget_type_id.dart'; 7 | 8 | class BaseWidgetType extends BaseData with HasTenantId { 9 | TenantId? tenantId; 10 | String name; 11 | String fqn; 12 | bool? deprecated; 13 | 14 | BaseWidgetType(this.name, this.fqn); 15 | 16 | BaseWidgetType.fromJson(Map json) 17 | : tenantId = json['tenantId'] != null 18 | ? TenantId.fromJson(json['tenantId']) 19 | : null, 20 | name = json['name'], 21 | fqn = json['fqn'], 22 | deprecated = json['deprecated'], 23 | super.fromJson(json); 24 | 25 | @override 26 | Map toJson() { 27 | var json = super.toJson(); 28 | json['name'] = name; 29 | json['fqn'] = fqn; 30 | if (tenantId != null) { 31 | json['tenantId'] = tenantId!.toJson(); 32 | } 33 | if (deprecated != null) { 34 | json['deprecated'] = deprecated; 35 | } 36 | return json; 37 | } 38 | 39 | @override 40 | TenantId? getTenantId() { 41 | return tenantId; 42 | } 43 | 44 | @override 45 | String toString() { 46 | return 'BaseWidgetType{${baseWidgetTypeString()}}'; 47 | } 48 | 49 | String baseWidgetTypeString([String? toStringBody]) { 50 | return '${baseDataString('tenantId: $tenantId, name: $name, fqn: $fqn, deprecated: $deprecated, ${toStringBody != null ? ', ' + toStringBody : ''}')}'; 51 | } 52 | } 53 | 54 | class WidgetTypeInfo extends BaseWidgetType { 55 | String? image; 56 | String? description; 57 | String widgetType; 58 | 59 | WidgetTypeInfo(String name, String fqn, this.widgetType) : super(name, fqn); 60 | 61 | WidgetTypeInfo.fromJson(Map json) 62 | : image = json['image'], 63 | description = json['description'], 64 | widgetType = json['widgetType'], 65 | super.fromJson(json); 66 | 67 | @override 68 | String toString() { 69 | return 'WidgetTypeInfo{${baseWidgetTypeString('widgetType: $widgetType, image: ${image != null ? '[' + image!.substring(0, min(30, image!.length)) + '...]' : 'null'}, description: $description')}}'; 70 | } 71 | } 72 | 73 | class WidgetType extends BaseWidgetType { 74 | Map descriptor; 75 | 76 | WidgetType(String name, String fqn, this.descriptor) : super(name, fqn); 77 | 78 | WidgetType.fromJson(Map json) 79 | : descriptor = json['descriptor'], 80 | super.fromJson(json); 81 | 82 | @override 83 | Map toJson() { 84 | var json = super.toJson(); 85 | json['descriptor'] = descriptor; 86 | return json; 87 | } 88 | 89 | @override 90 | String toString() { 91 | return 'WidgetType{${widgetTypeString()}}'; 92 | } 93 | 94 | String widgetTypeString([String? toStringBody]) { 95 | return '${baseWidgetTypeString('descriptor: $descriptor${toStringBody != null ? ', ' + toStringBody : ''}')}'; 96 | } 97 | } 98 | 99 | class WidgetTypeDetails extends WidgetType { 100 | String? image; 101 | String? description; 102 | WidgetTypeId? externalId; 103 | 104 | WidgetTypeDetails(String name, String fqn, Map descriptor) 105 | : super(name, fqn, descriptor); 106 | 107 | WidgetTypeDetails.fromJson(Map json) 108 | : image = json['image'], 109 | description = json['description'], 110 | externalId = json['externalId'], 111 | super.fromJson(json); 112 | 113 | @override 114 | Map toJson() { 115 | var json = super.toJson(); 116 | if (image != null) { 117 | json['image'] = image; 118 | } 119 | if (description != null) { 120 | json['description'] = description; 121 | } 122 | if (externalId != null) { 123 | json['externalId'] = externalId; 124 | } 125 | return json; 126 | } 127 | 128 | @override 129 | String toString() { 130 | return 'WidgetTypeDetails{${widgetTypeString('image: ${image != null ? '[' + image!.substring(0, min(30, image!.length)) + '...]' : 'null'}, ' 131 | 'description: $description, externalId: $externalId')}}'; 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /lib/src/service/asset_profile_service.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import '../http/http_utils.dart'; 4 | import '../model/asset_models.dart'; 5 | import '../model/page/page_data.dart'; 6 | import '../model/page/page_link.dart'; 7 | import '../thingsboard_client_base.dart'; 8 | 9 | PageData parseAssetProfilePageData(Map json) { 10 | return PageData.fromJson(json, (json) => AssetProfile.fromJson(json)); 11 | } 12 | 13 | PageData parseAssetProfileInfoPageData( 14 | Map json) { 15 | return PageData.fromJson(json, (json) => AssetProfileInfo.fromJson(json)); 16 | } 17 | 18 | class AssetProfileService { 19 | final ThingsboardClient _tbClient; 20 | 21 | factory AssetProfileService(ThingsboardClient tbClient) { 22 | return AssetProfileService._internal(tbClient); 23 | } 24 | 25 | AssetProfileService._internal(this._tbClient); 26 | 27 | Future> getAssetProfiles(PageLink pageLink, 28 | {RequestConfig? requestConfig}) async { 29 | var response = await _tbClient.get>( 30 | '/api/assetProfiles', 31 | queryParameters: pageLink.toQueryParameters(), 32 | options: defaultHttpOptionsFromConfig(requestConfig)); 33 | return _tbClient.compute(parseAssetProfilePageData, response.data!); 34 | } 35 | 36 | Future getAssetProfile(String assetProfileId, 37 | {RequestConfig? requestConfig}) async { 38 | return nullIfNotFound( 39 | (RequestConfig requestConfig) async { 40 | var response = await _tbClient.get>( 41 | '/api/assetProfile/$assetProfileId', 42 | options: defaultHttpOptionsFromConfig(requestConfig)); 43 | return response.data != null 44 | ? AssetProfile.fromJson(response.data!) 45 | : null; 46 | }, 47 | requestConfig: requestConfig, 48 | ); 49 | } 50 | 51 | Future saveAssetProfile(AssetProfile assetProfile, 52 | {RequestConfig? requestConfig}) async { 53 | var response = await _tbClient.post>( 54 | '/api/assetProfile', 55 | data: jsonEncode(assetProfile), 56 | options: defaultHttpOptionsFromConfig(requestConfig)); 57 | return AssetProfile.fromJson(response.data!); 58 | } 59 | 60 | Future deleteAssetProfile(String assetProfileId, 61 | {RequestConfig? requestConfig}) async { 62 | await _tbClient.delete('/api/assetProfile/$assetProfileId', 63 | options: defaultHttpOptionsFromConfig(requestConfig)); 64 | } 65 | 66 | Future setDefaultAssetProfile(String assetProfileId, 67 | {RequestConfig? requestConfig}) async { 68 | var response = await _tbClient.post>( 69 | '/api/assetProfile/$assetProfileId/default', 70 | options: defaultHttpOptionsFromConfig(requestConfig)); 71 | return AssetProfile.fromJson(response.data!); 72 | } 73 | 74 | Future getDefaultAssetProfileInfo( 75 | {RequestConfig? requestConfig}) async { 76 | var response = await _tbClient.get>( 77 | '/api/assetProfileInfo/default', 78 | options: defaultHttpOptionsFromConfig(requestConfig)); 79 | return AssetProfileInfo.fromJson(response.data!); 80 | } 81 | 82 | Future getAssetProfileInfo(String assetProfileId, 83 | {RequestConfig? requestConfig}) async { 84 | return nullIfNotFound( 85 | (RequestConfig requestConfig) async { 86 | var response = await _tbClient.get>( 87 | '/api/assetProfileInfo/$assetProfileId', 88 | options: defaultHttpOptionsFromConfig(requestConfig)); 89 | return response.data != null 90 | ? AssetProfileInfo.fromJson(response.data!) 91 | : null; 92 | }, 93 | requestConfig: requestConfig, 94 | ); 95 | } 96 | 97 | Future> getAssetProfileInfos(PageLink pageLink, 98 | {RequestConfig? requestConfig}) async { 99 | var response = await _tbClient.get>( 100 | '/api/assetProfileInfos', 101 | queryParameters: pageLink.toQueryParameters(), 102 | options: defaultHttpOptionsFromConfig(requestConfig)); 103 | return _tbClient.compute(parseAssetProfileInfoPageData, response.data!); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /lib/src/service/tenant_profile_service.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import '../http/http_utils.dart'; 4 | import '../model/entity_models.dart'; 5 | import '../model/page/page_data.dart'; 6 | import '../model/page/page_link.dart'; 7 | import '../model/tenant_models.dart'; 8 | import '../thingsboard_client_base.dart'; 9 | 10 | PageData parseTenantProfilePageData(Map json) { 11 | return PageData.fromJson(json, (json) => TenantProfile.fromJson(json)); 12 | } 13 | 14 | PageData parseTenantProfileInfoPageData(Map json) { 15 | return PageData.fromJson(json, (json) => EntityInfo.fromJson(json)); 16 | } 17 | 18 | class TenantProfileService { 19 | final ThingsboardClient _tbClient; 20 | 21 | factory TenantProfileService(ThingsboardClient tbClient) { 22 | return TenantProfileService._internal(tbClient); 23 | } 24 | 25 | TenantProfileService._internal(this._tbClient); 26 | 27 | Future getTenantProfile(String tenantProfileId, 28 | {RequestConfig? requestConfig}) async { 29 | return nullIfNotFound( 30 | (RequestConfig requestConfig) async { 31 | var response = await _tbClient.get>( 32 | '/api/tenantProfile/$tenantProfileId', 33 | options: defaultHttpOptionsFromConfig(requestConfig)); 34 | return response.data != null 35 | ? TenantProfile.fromJson(response.data!) 36 | : null; 37 | }, 38 | requestConfig: requestConfig, 39 | ); 40 | } 41 | 42 | Future getTenantProfileInfo(String tenantProfileId, 43 | {RequestConfig? requestConfig}) async { 44 | return nullIfNotFound( 45 | (RequestConfig requestConfig) async { 46 | var response = await _tbClient.get>( 47 | '/api/tenantProfileInfo/$tenantProfileId', 48 | options: defaultHttpOptionsFromConfig(requestConfig)); 49 | return response.data != null 50 | ? EntityInfo.fromJson(response.data!) 51 | : null; 52 | }, 53 | requestConfig: requestConfig, 54 | ); 55 | } 56 | 57 | Future getDefaultTenantProfileInfo( 58 | {RequestConfig? requestConfig}) async { 59 | var response = await _tbClient.get>( 60 | '/api/tenantProfileInfo/default', 61 | options: defaultHttpOptionsFromConfig(requestConfig)); 62 | return EntityInfo.fromJson(response.data!); 63 | } 64 | 65 | Future saveTenantProfile(TenantProfile tenantProfile, 66 | {RequestConfig? requestConfig}) async { 67 | var response = await _tbClient.post>( 68 | '/api/tenantProfile', 69 | data: jsonEncode(tenantProfile), 70 | options: defaultHttpOptionsFromConfig(requestConfig)); 71 | return TenantProfile.fromJson(response.data!); 72 | } 73 | 74 | Future deleteTenantProfile(String tenantProfileId, 75 | {RequestConfig? requestConfig}) async { 76 | await _tbClient.delete('/api/tenantProfile/$tenantProfileId', 77 | options: defaultHttpOptionsFromConfig(requestConfig)); 78 | } 79 | 80 | Future setDefaultTenantProfile(String tenantProfileId, 81 | {RequestConfig? requestConfig}) async { 82 | var response = await _tbClient.post>( 83 | '/api/tenantProfile/$tenantProfileId/default', 84 | options: defaultHttpOptionsFromConfig(requestConfig)); 85 | return TenantProfile.fromJson(response.data!); 86 | } 87 | 88 | Future> getTenantProfiles(PageLink pageLink, 89 | {RequestConfig? requestConfig}) async { 90 | var response = await _tbClient.get>( 91 | '/api/tenantProfiles', 92 | queryParameters: pageLink.toQueryParameters(), 93 | options: defaultHttpOptionsFromConfig(requestConfig)); 94 | return _tbClient.compute(parseTenantProfilePageData, response.data!); 95 | } 96 | 97 | Future> getTenantProfileInfos(PageLink pageLink, 98 | {RequestConfig? requestConfig}) async { 99 | var response = await _tbClient.get>( 100 | '/api/tenantProfileInfos', 101 | queryParameters: pageLink.toQueryParameters(), 102 | options: defaultHttpOptionsFromConfig(requestConfig)); 103 | return _tbClient.compute(parseTenantProfileInfoPageData, response.data!); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /lib/src/model/group_permission_models.dart: -------------------------------------------------------------------------------- 1 | import 'entity_type_models.dart'; 2 | import 'id/entity_group_id.dart'; 3 | import 'id/entity_id.dart'; 4 | import 'id/role_id.dart'; 5 | import 'id/tenant_id.dart'; 6 | import 'base_data.dart'; 7 | import 'has_name.dart'; 8 | import 'id/group_permission_id.dart'; 9 | import 'tenant_entity.dart'; 10 | import 'role_models.dart'; 11 | 12 | class GroupPermission extends BaseData 13 | implements HasName, TenantEntity { 14 | TenantId? tenantId; 15 | EntityGroupId? userGroupId; 16 | RoleId roleId; 17 | EntityGroupId? entityGroupId; 18 | EntityType? entityGroupType; 19 | bool isPublic; 20 | 21 | GroupPermission( 22 | {required this.userGroupId, 23 | required this.roleId, 24 | this.isPublic = false, 25 | this.entityGroupId, 26 | this.entityGroupType}); 27 | 28 | GroupPermission.fromJson(Map json) 29 | : tenantId = json['tenantId'] != null 30 | ? TenantId.fromJson(json['tenantId']) 31 | : null, 32 | userGroupId = json['userGroupId'] != null 33 | ? EntityGroupId.fromJson(json['userGroupId']) 34 | : null, 35 | roleId = RoleId.fromJson(json['roleId']), 36 | entityGroupId = json['entityGroupId'] != null 37 | ? EntityGroupId.fromJson(json['entityGroupId']) 38 | : null, 39 | entityGroupType = json['entityGroupType'] != null 40 | ? entityTypeFromString(json['entityGroupType']) 41 | : null, 42 | isPublic = json['isPublic'] != null ? json['isPublic'] : false, 43 | super.fromJson(json); 44 | 45 | @override 46 | Map toJson() { 47 | var json = super.toJson(); 48 | if (tenantId != null) { 49 | json['tenantId'] = tenantId!.toJson(); 50 | } 51 | if (userGroupId != null) { 52 | json['userGroupId'] = userGroupId!.toJson(); 53 | } 54 | json['roleId'] = roleId.toJson(); 55 | if (entityGroupId != null) { 56 | json['entityGroupId'] = entityGroupId!.toJson(); 57 | } 58 | if (entityGroupType != null) { 59 | json['entityGroupType'] = entityGroupType!.toShortString(); 60 | } 61 | json['isPublic'] = isPublic; 62 | return json; 63 | } 64 | 65 | @override 66 | TenantId? getTenantId() { 67 | return tenantId; 68 | } 69 | 70 | @override 71 | String getName() { 72 | if (entityGroupId != null && entityGroupType != null) { 73 | return 'GROUP_[$userGroupId]_[$roleId]_[$entityGroupId]_[${entityGroupType!.toShortString()}]'; 74 | } else { 75 | return 'GENERIC_[$userGroupId]_[$roleId]'; 76 | } 77 | } 78 | 79 | @override 80 | EntityType getEntityType() { 81 | return EntityType.GROUP_PERMISSION; 82 | } 83 | 84 | @override 85 | String toString() { 86 | return 'GroupPermission{${groupPermissionString()}}'; 87 | } 88 | 89 | String groupPermissionString([String? toStringBody]) { 90 | return '${baseDataString('tenantId: $tenantId, userGroupId: $userGroupId, roleId: $roleId, entityGroupId: $entityGroupId, entityGroupType: $entityGroupType, ' 91 | 'isPublic: $isPublic${toStringBody != null ? ', ' + toStringBody : ''}')}'; 92 | } 93 | } 94 | 95 | class GroupPermissionInfo extends GroupPermission { 96 | Role role; 97 | String? entityGroupName; 98 | EntityId? entityGroupOwnerId; 99 | String? entityGroupOwnerName; 100 | String userGroupName; 101 | EntityId userGroupOwnerId; 102 | String userGroupOwnerName; 103 | bool readOnly; 104 | 105 | GroupPermissionInfo.fromJson(Map json) 106 | : role = Role.fromJson(json['role']), 107 | entityGroupName = json['entityGroupName'], 108 | entityGroupOwnerId = json['entityGroupOwnerId'] != null 109 | ? EntityId.fromJson(json['entityGroupOwnerId']) 110 | : null, 111 | entityGroupOwnerName = json['entityGroupOwnerName'], 112 | userGroupName = json['userGroupName'], 113 | userGroupOwnerId = EntityId.fromJson(json['userGroupOwnerId']), 114 | userGroupOwnerName = json['userGroupOwnerName'], 115 | readOnly = json['readOnly'], 116 | super.fromJson(json); 117 | 118 | @override 119 | String toString() { 120 | return 'GroupPermissionInfo{${groupPermissionString('role: $role, entityGroupName: $entityGroupName, entityGroupOwnerId: $entityGroupOwnerId, ' 121 | 'entityGroupOwnerName: $entityGroupOwnerName, userGroupName: $userGroupName, userGroupOwnerId: $userGroupOwnerId, userGroupOwnerName: $userGroupOwnerName, readOnly: $readOnly')}'; 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /lib/src/model/id/entity_id.dart: -------------------------------------------------------------------------------- 1 | import 'blob_entity_id.dart'; 2 | import 'converter_id.dart'; 3 | import 'entity_group_id.dart'; 4 | import 'group_permission_id.dart'; 5 | import 'integration_id.dart'; 6 | import 'role_id.dart'; 7 | import 'scheduler_event_id.dart'; 8 | import 'ota_package_id.dart'; 9 | import 'alarm_id.dart'; 10 | import 'api_usage_state_id.dart'; 11 | import 'asset_id.dart'; 12 | import 'dashboard_id.dart'; 13 | import 'device_profile_id.dart'; 14 | import 'asset_profile_id.dart'; 15 | import 'edge_id.dart'; 16 | import 'entity_view_id.dart'; 17 | import 'rule_chain_id.dart'; 18 | import 'rule_node_id.dart'; 19 | import 'tb_resource_id.dart'; 20 | import 'tenant_profile_id.dart'; 21 | import 'user_id.dart'; 22 | import 'widget_type_id.dart'; 23 | import 'widgets_bundle_id.dart'; 24 | import 'customer_id.dart'; 25 | import 'device_id.dart'; 26 | import 'tenant_id.dart'; 27 | import 'rpc_id.dart'; 28 | import 'queue_id.dart'; 29 | import 'notification_id.dart'; 30 | import 'notification_request_id.dart'; 31 | import 'notification_rule_id.dart'; 32 | import 'notification_target_id.dart'; 33 | import 'notification_template_id.dart'; 34 | 35 | import '../entity_type_models.dart'; 36 | import './has_uuid.dart'; 37 | 38 | abstract class EntityId extends HasUuid { 39 | EntityType entityType; 40 | 41 | EntityId(this.entityType, String id) : super(id); 42 | 43 | factory EntityId.fromJson(Map json) { 44 | if (json.containsKey('entityType') && json.containsKey('id')) { 45 | var entityType = entityTypeFromString(json['entityType']); 46 | String uuid = json['id']; 47 | return EntityId.fromTypeAndUuid(entityType, uuid); 48 | } else { 49 | throw FormatException('Missing entityType or id!'); 50 | } 51 | } 52 | 53 | factory EntityId.fromTypeAndUuid(EntityType type, String uuid) { 54 | switch (type) { 55 | case EntityType.TENANT: 56 | return TenantId(uuid); 57 | case EntityType.TENANT_PROFILE: 58 | return TenantProfileId(uuid); 59 | case EntityType.CUSTOMER: 60 | return CustomerId(uuid); 61 | case EntityType.USER: 62 | return UserId(uuid); 63 | case EntityType.DASHBOARD: 64 | return DashboardId(uuid); 65 | case EntityType.ASSET: 66 | return AssetId(uuid); 67 | case EntityType.DEVICE: 68 | return DeviceId(uuid); 69 | case EntityType.DEVICE_PROFILE: 70 | return DeviceProfileId(uuid); 71 | case EntityType.ASSET_PROFILE: 72 | return AssetProfileId(uuid); 73 | case EntityType.ALARM: 74 | return AlarmId(uuid); 75 | case EntityType.RULE_CHAIN: 76 | return RuleChainId(uuid); 77 | case EntityType.RULE_NODE: 78 | return RuleNodeId(uuid); 79 | case EntityType.EDGE: 80 | return EdgeId(uuid); 81 | case EntityType.ENTITY_VIEW: 82 | return EntityViewId(uuid); 83 | case EntityType.WIDGETS_BUNDLE: 84 | return WidgetsBundleId(uuid); 85 | case EntityType.WIDGET_TYPE: 86 | return WidgetTypeId(uuid); 87 | case EntityType.API_USAGE_STATE: 88 | return ApiUsageStateId(uuid); 89 | case EntityType.TB_RESOURCE: 90 | return TbResourceId(uuid); 91 | case EntityType.OTA_PACKAGE: 92 | return OtaPackageId(uuid); 93 | case EntityType.RPC: 94 | return RpcId(uuid); 95 | case EntityType.ENTITY_GROUP: 96 | return EntityGroupId(uuid); 97 | case EntityType.CONVERTER: 98 | return ConverterId(uuid); 99 | case EntityType.INTEGRATION: 100 | return IntegrationId(uuid); 101 | case EntityType.SCHEDULER_EVENT: 102 | return SchedulerEventId(uuid); 103 | case EntityType.BLOB_ENTITY: 104 | return BlobEntityId(uuid); 105 | case EntityType.ROLE: 106 | return RoleId(uuid); 107 | case EntityType.GROUP_PERMISSION: 108 | return GroupPermissionId(uuid); 109 | case EntityType.QUEUE: 110 | return QueueId(uuid); 111 | case EntityType.NOTIFICATION_TARGET: 112 | return NotificationTargetId(uuid); 113 | case EntityType.NOTIFICATION_TEMPLATE: 114 | return NotificationTemplateId(uuid); 115 | case EntityType.NOTIFICATION_REQUEST: 116 | return NotificationRequestId(uuid); 117 | case EntityType.NOTIFICATION: 118 | return NotificationId(uuid); 119 | case EntityType.NOTIFICATION_RULE: 120 | return NotificationRuleId(uuid); 121 | } 122 | } 123 | 124 | @override 125 | Map toJson() { 126 | var json = super.toJson(); 127 | json['entityType'] = entityType.toShortString(); 128 | return json; 129 | } 130 | } 131 | --------------------------------------------------------------------------------