From a62ecac4e0514fdc5c68642a396c0d64ebfcea39 Mon Sep 17 00:00:00 2001 From: Chris D Date: Thu, 30 Nov 2023 18:56:32 -0500 Subject: [PATCH] 'dependency bump, corrections to cli README, GetPresetTour(s)' --- CHANGELOG.md | 8 + README.md | 14 +- bin/README.md | 157 ++++++++++++++---- lib/meta.dart | 2 +- lib/ptz.dart | 6 + lib/src/cmd/onvif_ptz_command.dart | 77 ++++++++- .../model/ptz/get_preset_tour_response.dart | 23 +++ .../model/ptz/get_preset_tour_response.g.dart | 20 +++ .../model/ptz/get_preset_tours_response.dart | 36 ++++ .../ptz/get_preset_tours_response.g.dart | 19 +++ lib/src/model/ptz/preset_tour.dart | 58 +++++++ lib/src/model/ptz/preset_tour.g.dart | 34 ++++ lib/src/model/ptz/ptz_preset_tour_spot.dart | 40 +++++ lib/src/model/ptz/ptz_preset_tour_spot.g.dart | 25 +++ .../ptz_preset_tour_starting_condition.dart | 61 +++++++ .../ptz_preset_tour_starting_condition.g.dart | 35 ++++ lib/src/model/ptz/ptz_preset_tour_status.dart | 54 ++++++ .../model/ptz/ptz_preset_tour_status.g.dart | 32 ++++ lib/src/ptz.dart | 31 ++++ lib/src/soap/ptz.dart | 51 ++++++ pubspec.yaml | 14 +- tool/README.md | 12 +- tool/config.sample.yaml | 24 --- tool/reddit_post.md | 18 -- 24 files changed, 756 insertions(+), 95 deletions(-) create mode 100644 lib/src/model/ptz/get_preset_tour_response.dart create mode 100644 lib/src/model/ptz/get_preset_tour_response.g.dart create mode 100644 lib/src/model/ptz/get_preset_tours_response.dart create mode 100644 lib/src/model/ptz/get_preset_tours_response.g.dart create mode 100644 lib/src/model/ptz/preset_tour.dart create mode 100644 lib/src/model/ptz/preset_tour.g.dart create mode 100644 lib/src/model/ptz/ptz_preset_tour_spot.dart create mode 100644 lib/src/model/ptz/ptz_preset_tour_spot.g.dart create mode 100644 lib/src/model/ptz/ptz_preset_tour_starting_condition.dart create mode 100644 lib/src/model/ptz/ptz_preset_tour_starting_condition.g.dart create mode 100644 lib/src/model/ptz/ptz_preset_tour_status.dart create mode 100644 lib/src/model/ptz/ptz_preset_tour_status.g.dart delete mode 100644 tool/config.sample.yaml delete mode 100644 tool/reddit_post.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 82974d9..d6bcad3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 2.1.3+4 + +* dependency bump +* corrections to cli README +* PTZ + * GetPresetTour + * GetPresetTours + ## 2.1.3+3 * accept null values in ProbeMatch diff --git a/README.md b/README.md index a2a4239..e96f9d0 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ To use this package in your code, first add the dependency to your project: ```yml dependencies: ... - easy_onvif: ^2.1.3+3 + easy_onvif: ^2.1.3+4 ``` If you need additional help getting started with dart, check out these [guides](https://dart.dev/guides). @@ -260,6 +260,8 @@ Please see the cli documentation [README.md](https://github.com/faithoflifedev/e | GetConfigurationOptions | getConfigurationOptions | `Future` | [x\] | | GetConfigurations | getConfigurations | `Future>` | [x\] | | GetPresets | getPresets | `Future>` | [x\] | +| GetPresetTour | getPresetTour | `Future` | [ \] | +| GetPresetTours | getPresetTours | `Future>` | [ \] | | GetServiceCapabilities | getServiceCapabilities | `Future` | [x\] | | GetStatus | getStatus | `Future` | [x\] | | GotoHomePosition | gotoHomePosition | `Future` | [x\] | @@ -323,17 +325,17 @@ The values returned by the Onvif API `GetDeviceInformation` call. | Manufacturer | Model | Known Issue | | ------------------ | -------------- | -------------------------------- | | Happytimesoft | IPCamera | limited capabilities | -| D-Link Corporation | DCS-6511 | commands not implemented¹ | -| ONVIF | ENP1A14-IR/25X | commands not implemented² | +| ONVIF | ENP1A14-IR/25X | commands not implemented¹ | +| D-Link Corporation | DCS-6511 | commands not implemented² | | NONE | GX728MF-IR28 | commands not implemented³ | | LOREX | LNB4421SB | testing in progress | -¹ The following are not implemented for the ENP1A14-IR/25X: +¹ The ENP1A14-IR/25X does not support the following commands: * Recordings * `CreateRecording` * `DeleteRecording` -² The following are not implemented for the DCS-6511: +² The DCS-6511 does not support the following commands: * Device Management: * `GetServices` * `GetServiceCapabilities` @@ -346,7 +348,7 @@ The values returned by the Onvif API `GetDeviceInformation` call. * PTZ: * not tested -³ The following are not implemented for the GX728MF-IR28: +³ The GX728MF-IR28 does not support the following commands: * Device Management: * `GetSystemUris` * Media1: diff --git a/bin/README.md b/bin/README.md index 23a182e..fae2244 100644 --- a/bin/README.md +++ b/bin/README.md @@ -864,25 +864,33 @@ Usage: onvif ptz [arguments] -h, --help Print this usage information. Available subcommands: - absolute-move Operation to move pan,tilt or zoom to a absolute destination. - continuous-move Operation for continuous Pan/Tilt and Zoom movements. - get-configuration Get a specific PTZconfiguration from the device, identified by its reference token or name. - get-configurations Get all the existing PTZConfigurations from the device. - get-presets Operation to request all PTZ presets for the PTZNode in the selected profile. - get-status Operation to request PTZ status for the Node in the selected profile. - goto-preset Operation to go to a saved preset position for the PTZNode in the selected profile. - move Operation for Relative Pan/Tilt and Zoom Move, without Zoom. - move-down Operation for a single step tilt down operation. - move-left Operation for a single step pan left operation. - move-right Operation for a single step tilt upwards operation - move-up Operation for a single step tilt upwards operation. - relative-move Operation for Relative Pan/Tilt and Zoom Move. - remove-preset Operation to remove a PTZ preset for the Node in the selected profile. - set-preset The SetPreset command saves the current device position parameters so that the device can move to the saved preset position through the GotoPreset operation. - stop Operation to stop ongoing pan, tilt and zoom movements of absolute relative and continuous type. - zoom Operation for zoom. - zoom-in Operation for a single step zoom in operation. - zoom-out Operation for a single step zoom out operation. + absolute-move Operation to move pan,tilt or zoom to a absolute destination. + continuous-move Operation for continuous Pan/Tilt and Zoom movements. + get-compatible-configurations Contains the token of an existing media profile the configurations shall be compatible with. + get-configuration Get a specific PTZconfiguration from the device, identified by its reference token or name. + get-configuration-options Token of an existing configuration that the options are intended for. + get-configurations Get all the existing PTZConfigurations from the device. + get-current-preset Helper function to get the matching preset for the current PtzPosition and Zoom if there is a match + get-preset-tour Operation to request a specific PTZ preset tour in the selected media profile. + get-preset-tours Operation to request PTZ preset tours in the selected media profiles. + get-presets Operation to request all PTZ presets for the PTZNode in the selected profile. + get-service-capabilities Returns the capabilities of the PTZ service. The result is returned in a typed answer. + get-status Operation to request PTZ status for the Node in the selected profile. + goto-home-position Operation to move the PTZ device to it's "home" position. The operation is supported if the HomeSupported element in the PTZNode is true. + goto-preset Operation to go to a saved preset position for the PTZNode in the selected profile. + move Operation for Relative Pan/Tilt Move without Zoom. + move-down Operation for a single step tilt down operation. + move-left Operation for a single step pan left operation. + move-right Operation for a single step pan right operation + move-up Operation for a single step tilt upwards operation. + relative-move Operation for Relative Pan/Tilt and Zoom Move. + remove-preset Operation to remove a PTZ preset for the Node in the selected profile. + set-home-position Operation to save current position as the home position. The SetHomePosition command returns with a failure if the “home” position is fixed and cannot be overwritten. If the SetHomePosition is successful, it is possible to recall the Home Position with the GotoHomePosition command. + set-preset The SetPreset command saves the current device position parameters so that the device can move to the saved preset position through the GotoPreset operation. + stop Operation to stop ongoing pan, tilt and zoom movements of absolute relative and continuous type. + zoom Operation for zoom. + zoom-in Operation for a single step zoom in operation. + zoom-out Operation for a single step zoom out operation. ``` #### ptz absolute-move @@ -919,6 +927,20 @@ Usage: onvif ptz continuous-move [arguments] --pan-tilt-zoom= (mandatory) A Position vector specifying the absolute target position zoom. ``` +### ptz get-compatible-configurations + +```sh +onvif ptz get-compatible-configurations --help +``` + +```text +Contains the token of an existing media profile the configurations shall be compatible with. + +Usage: onvif ptz get-compatible-configurations [arguments] +-h, --help Print this usage information. +-t, --profile-token= (mandatory) The ProfileToken element indicates the media profile to use and will define the source and dimensions of the snapshot. +``` + #### ptz get-configuration ```sh @@ -933,6 +955,20 @@ Usage: onvif ptz get-configuration [arguments] -t, --ptz-configuration-token= (mandatory) Token of the requested PTZConfiguration. ``` +#### ptz get-configuration-options + +```sh +onvif ptz get-configuration-options --help +``` + +```text +List supported coordinate systems including their range limitations. + +Usage: onvif ptz get-configuration-options [arguments] +-h, --help Print this usage information. +-t, --configuration-token= (mandatory) Token of an existing configuration that the options are intended for. +``` + #### ptz get-configurations ```sh @@ -946,6 +982,49 @@ Usage: onvif ptz get-configurations [arguments] -h, --help Print this usage information. ``` +#### ptz get-current-preset + +```sh +onvif ptz get-current-preset --help +``` + +```text +Helper function to get the matching preset for the current PtzPosition and Zoom if there is a match + +Usage: onvif ptz get-current-preset [arguments] +-h, --help Print this usage information. +-t, --profile-token= (mandatory) The ProfileToken element indicates the media profile to use and will define the source and dimensions of the snapshot. +``` + +#### ptz get-preset-tour + +```sh +onvif ptz get-preset-tour --help +``` + +```text +Operation to request a specific PTZ preset tour in the selected media profile. + +Usage: onvif ptz get-preset-tour [arguments] +-h, --help Print this usage information. +-t, --profile-token= (mandatory) A reference to the MediaProfile where the operation should take place. + --preset-tour-token= (mandatory) A requested preset tour token. +``` + +#### ptz get-preset-tours + +```sh +onvif ptz get-preset-tours --help +``` + +```text +Operation to request PTZ preset tours in the selected media profiles. + +Usage: onvif ptz get-preset-tours [arguments] +-h, --help Print this usage information. +-t, --profile-token= (mandatory) A reference to the MediaProfile where the operation should take place. +``` + #### ptz get-presets ```sh @@ -961,6 +1040,18 @@ Usage: onvif ptz get-presets [arguments] --limit= Limit the number of presets returned ``` +#### ptz get-service-capabilities + +```sh +onvif ptz get-service-capabilities --help +``` + +```text +Returns the capabilities of the PTZ service. The result is returned in a typed answer. + +Usage: onvif ptz get-service-capabilities [arguments] +``` + #### ptz get-status ```sh @@ -1098,6 +1189,20 @@ Usage: onvif ptz remove-preset [arguments] --preset-token= (mandatory) A requested preset token. ``` +#### ptz set-home-position + +```sh +onvif ptz set-home-position --help +``` + +```text +Operation to save current position as the home position. The SetHomePosition command returns with a failure if the “home” position is fixed and cannot be overwritten. If the SetHomePosition is successful, it is possible to recall the Home Position with the GotoHomePosition command. + +Usage: onvif ptz set-home-position [arguments] +-h, --help Print this usage information. +-t, --profile-token= (mandatory) A reference to the MediaProfile where the operation should be set. +``` + #### ptz set-preset ```sh @@ -1174,20 +1279,6 @@ Usage: onvif ptz zoom-out [arguments] --step= The amount of movement for the step. ``` -#### ptz get-current-preset - -```sh -onvif ptz get-current-preset --help -``` - -```text -Helper function to get the matching preset for the current PtzPosition and Zoom if there is a match - -Usage: onvif ptz get-current-preset [arguments] --h, --help Print this usage information. --t, --profile-token= (mandatory) The ProfileToken element indicates the media profile to use and will define the source and dimensions of the snapshot. -``` - ### recordings ```sh diff --git a/lib/meta.dart b/lib/meta.dart index da90682..20e418b 100644 --- a/lib/meta.dart +++ b/lib/meta.dart @@ -3,4 +3,4 @@ import 'dart:convert' show json; final pubSpec = json.decode( - '{"name":"easy_onvif","version":"2.1.3+3","homepage":"https://github.com/faithoflifedev/easy_onvif","environment":{"sdk":">=3.0.0 <4.0.0"},"description":"A pure Dart library designed primarily for command line automation of Onvif compatible devices, but can be used anywhere Dart is used.","dependencies":{"args":"^2.4.2","crypto":"^3.0.3","dio":"^5.3.3","ffi":"^2.1.0","html_unescape":"^2.0.0","intl":"^0.18.1","json_annotation":"^4.8.1","loggy":"^2.0.3","path":"^1.8.3","shelf":"^1.4.1","shelf_router":"^1.1.4","sprintf":"^7.0.0","universal_io":"^2.2.2","uuid":"^4.1.0","xml":"^6.3.0","xml2json":"^6.2.0","yaml":"^3.1.2"},"dev_dependencies":{"build_runner":"^2.4.5","grinder":"^0.9.4","json_serializable":"^6.7.1","lints":"^3.0.0","mustache_template":"^2.0.0","process_run":"^0.13.0","pub_semver":"^2.1.4","publish_tools":"^0.1.0+12","pubspec":"^2.3.0","test":"^1.24.8"},"executables":{"onvif":""},"repository":"https://github.com/faithoflifedev/easy_onvif.git"}'); + '{"name":"easy_onvif","version":"2.1.3+4","homepage":"https://github.com/faithoflifedev/easy_onvif","environment":{"sdk":">=3.0.0 <4.0.0"},"description":"A pure Dart library designed primarily for command line automation of Onvif compatible devices, but can be used anywhere Dart is used.","dependencies":{"args":"^2.4.2","crypto":"^3.0.3","dio":"^5.4.0","ffi":"^2.1.0","html_unescape":"^2.0.0","intl":"^0.18.1","json_annotation":"^4.8.1","loggy":"^2.0.3","path":"^1.8.3","shelf":"^1.4.1","shelf_router":"^1.1.4","sprintf":"^7.0.0","universal_io":"^2.2.2","uuid":"^4.2.1","xml":"^6.3.0","xml2json":"^6.2.1","yaml":"^3.1.2"},"dev_dependencies":{"build_runner":"^2.4.7","grinder":"^0.9.5","json_serializable":"^6.7.1","lints":"^3.0.0","mustache_template":"^2.0.0","process_run":"^0.13.0","pub_semver":"^2.1.4","publish_tools":"^0.1.0+12","pubspec":"^2.3.0","test":"^1.24.9"},"executables":{"onvif":""},"repository":"https://github.com/faithoflifedev/easy_onvif.git"}'); diff --git a/lib/ptz.dart b/lib/ptz.dart index 4f802bb..9df7808 100644 --- a/lib/ptz.dart +++ b/lib/ptz.dart @@ -8,13 +8,19 @@ export 'src/model/ptz/get_configuration_response.dart'; export 'src/model/ptz/get_configuration_options_response.dart'; export 'src/model/ptz/get_configurations_response.dart'; export 'src/model/ptz/get_presets_response.dart'; +export 'src/model/ptz/get_preset_tour_response.dart'; +export 'src/model/ptz/get_preset_tours_response.dart'; export 'src/model/ptz/get_service_capabilities_response.dart'; export 'src/model/ptz/get_status_response.dart'; export 'src/model/ptz/modal_options.dart'; export 'src/model/ptz/preset.dart'; +export 'src/model/ptz/preset_tour.dart'; export 'src/model/ptz/pt_control_direction.dart'; export 'src/model/ptz/ptz_configuration_options.dart'; export 'src/model/ptz/ptz_position.dart'; +export 'src/model/ptz/ptz_preset_tour_spot.dart'; +export 'src/model/ptz/ptz_preset_tour_starting_condition.dart'; +export 'src/model/ptz/ptz_preset_tour_status.dart'; export 'src/model/ptz/ptz_spaces.dart'; export 'src/model/ptz/ptz_status.dart'; export 'src/model/ptz/set_preset_response.dart'; diff --git a/lib/src/cmd/onvif_ptz_command.dart b/lib/src/cmd/onvif_ptz_command.dart index 1b51111..3fe20b9 100644 --- a/lib/src/cmd/onvif_ptz_command.dart +++ b/lib/src/cmd/onvif_ptz_command.dart @@ -21,6 +21,8 @@ class OnvifPtzCommand extends Command { addSubcommand(OnvifGetConfigurationsPtzCommand()); addSubcommand(OnvifGetCurrentPresetPtzCommand()); addSubcommand(OnvifGetPresetsPtzCommand()); + addSubcommand(OnvifGetPresetTourPtzCommand()); + addSubcommand(OnvifGetPresetToursPtzCommand()); addSubcommand(OnvifGetServiceCapabilitiesPtzCommand()); addSubcommand(OnvifGetStatusPtzCommand()); addSubcommand(OnvifGotoHomePositionPtzCommand()); @@ -253,7 +255,7 @@ class OnvifGetConfigurationPtzCommand extends OnvifHelperCommand { class OnvifGetConfigurationOptionsPtzCommand extends OnvifHelperCommand { @override String get description => - 'Token of an existing configuration that the options are intended for.'; + 'List supported coordinate systems including their range limitations.'; @override String get name => 'get-configuration-options'; @@ -323,6 +325,79 @@ class OnvifGetConfigurationsPtzCommand extends OnvifHelperCommand { } } +/// Operation to request a specific PTZ preset tour in the selected media profile. +class OnvifGetPresetTourPtzCommand extends OnvifHelperCommand { + @override + String get description => + 'Operation to request a specific PTZ preset tour in the selected media profile.'; + + @override + String get name => 'get-preset-tour'; + + OnvifGetPresetTourPtzCommand() { + argParser + ..addOption('profile-token', + abbr: 't', + valueHelp: 'token', + mandatory: true, + help: + 'A reference to the MediaProfile where the operation should take place.') + ..addOption('preset-tour-token', + valueHelp: 'token', + mandatory: true, + help: 'A requested preset tour token.'); + } + + @override + void run() async { + await initializeOnvif(); + + try { + final presetTour = await ptz.getPresetTour( + argResults!['profile-token'], + presetTourToken: argResults!['preset-tour-token'], + ); + + print(presetTour); + } on DioException catch (err) { + throw UsageException('API usage error:', err.usage); + } + } +} + +/// Operation to request PTZ preset tours in the selected media profiles. +class OnvifGetPresetToursPtzCommand extends OnvifHelperCommand { + @override + String get description => + 'Operation to request PTZ preset tours in the selected media profiles.'; + + @override + String get name => 'get-preset-tours'; + + OnvifGetPresetToursPtzCommand() { + argParser.addOption('profile-token', + abbr: 't', + valueHelp: 'token', + mandatory: true, + help: + 'A reference to the MediaProfile where the operation should take place.'); + } + + @override + void run() async { + await initializeOnvif(); + + try { + final presetTours = + await ptz.getPresetTours(argResults!['profile-token']); + + print(presetTours); + } on DioException catch (err) { + throw UsageException('API usage error:', err.usage); + } + } +} + /// Operation to request all PTZ presets for the PTZNode in the selected /// profile. The operation is supported if there is support for at least on PTZ /// preset by the PTZNode. diff --git a/lib/src/model/ptz/get_preset_tour_response.dart b/lib/src/model/ptz/get_preset_tour_response.dart new file mode 100644 index 0000000..543f6e0 --- /dev/null +++ b/lib/src/model/ptz/get_preset_tour_response.dart @@ -0,0 +1,23 @@ +import 'dart:convert'; + +import 'package:json_annotation/json_annotation.dart'; + +import 'preset_tour.dart'; + +part 'get_preset_tour_response.g.dart'; + +@JsonSerializable() +class GetPresetTourResponse { + @JsonKey(name: 'PresetTour') + final PresetTour presetTour; + + GetPresetTourResponse({required this.presetTour}); + + factory GetPresetTourResponse.fromJson(Map json) => + _$GetPresetTourResponseFromJson(json); + + Map toJson() => _$GetPresetTourResponseToJson(this); + + @override + String toString() => jsonEncode(toJson()); +} diff --git a/lib/src/model/ptz/get_preset_tour_response.g.dart b/lib/src/model/ptz/get_preset_tour_response.g.dart new file mode 100644 index 0000000..df5cb19 --- /dev/null +++ b/lib/src/model/ptz/get_preset_tour_response.g.dart @@ -0,0 +1,20 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'get_preset_tour_response.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +GetPresetTourResponse _$GetPresetTourResponseFromJson( + Map json) => + GetPresetTourResponse( + presetTour: + PresetTour.fromJson(json['PresetTour'] as Map), + ); + +Map _$GetPresetTourResponseToJson( + GetPresetTourResponse instance) => + { + 'PresetTour': instance.presetTour, + }; diff --git a/lib/src/model/ptz/get_preset_tours_response.dart b/lib/src/model/ptz/get_preset_tours_response.dart new file mode 100644 index 0000000..a637c64 --- /dev/null +++ b/lib/src/model/ptz/get_preset_tours_response.dart @@ -0,0 +1,36 @@ +import 'dart:convert'; + +import 'package:json_annotation/json_annotation.dart'; + +import 'preset_tour.dart'; + +part 'get_preset_tours_response.g.dart'; + +/// Operation to request PTZ preset tours in the selected media profiles. +@JsonSerializable() +class GetPresetToursResponse { + @JsonKey(name: 'PresetTour', fromJson: _unbound) + final List presetTours; + + GetPresetToursResponse({required this.presetTours}); + + factory GetPresetToursResponse.fromJson(Map json) => + _$GetPresetToursResponseFromJson(json); + + Map toJson() => _$GetPresetToursResponseToJson(this); + + @override + String toString() => jsonEncode(toJson()); + + static List _unbound(dynamic json) { + if (json == null) return []; + + if (json is List) { + return json + .map((e) => PresetTour.fromJson(e as Map)) + .toList(); + } + + return [PresetTour.fromJson(json as Map)]; + } +} diff --git a/lib/src/model/ptz/get_preset_tours_response.g.dart b/lib/src/model/ptz/get_preset_tours_response.g.dart new file mode 100644 index 0000000..9f18a1e --- /dev/null +++ b/lib/src/model/ptz/get_preset_tours_response.g.dart @@ -0,0 +1,19 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'get_preset_tours_response.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +GetPresetToursResponse _$GetPresetToursResponseFromJson( + Map json) => + GetPresetToursResponse( + presetTours: GetPresetToursResponse._unbound(json['PresetTour']), + ); + +Map _$GetPresetToursResponseToJson( + GetPresetToursResponse instance) => + { + 'PresetTour': instance.presetTours, + }; diff --git a/lib/src/model/ptz/preset_tour.dart b/lib/src/model/ptz/preset_tour.dart new file mode 100644 index 0000000..69e767e --- /dev/null +++ b/lib/src/model/ptz/preset_tour.dart @@ -0,0 +1,58 @@ +import 'dart:convert'; + +import 'package:easy_onvif/util.dart'; +import 'package:json_annotation/json_annotation.dart'; + +import 'ptz_preset_tour_spot.dart'; +import 'ptz_preset_tour_starting_condition.dart'; +import 'ptz_preset_tour_status.dart'; + +part 'preset_tour.g.dart'; + +@JsonSerializable() +class PresetTour { + /// Unique identifier of this preset tour. + @JsonKey(name: '@token') + final String token; + + /// Read only parameters to indicate the status of the preset tour. + @JsonKey(name: 'Name') + final String? name; + + /// Read only parameters to indicate the status of the preset tour. + @JsonKey(name: 'Status') + final PtzPresetTourStatus status; + + /// Auto Start flag of the preset tour. True allows the preset tour to be activated always. + @JsonKey(name: 'AutoStart', fromJson: OnvifUtil.mappedToBool) + final bool autoStart; + + /// Parameters to specify the detail behavior of the preset tour. + @JsonKey(name: 'StartingCondition') + final PtzPresetTourStartingCondition startingCondition; + + /// A list of detail of touring spots including preset positions. + @JsonKey(name: 'TourSpot') + final PtzPresetTourSpot? tourSpot; + + @JsonKey(name: 'Extension') + final dynamic extension; + + PresetTour({ + required this.token, + this.name, + required this.status, + required this.autoStart, + required this.startingCondition, + this.tourSpot, + this.extension, + }); + + factory PresetTour.fromJson(Map json) => + _$PresetTourFromJson(json); + + Map toJson() => _$PresetTourToJson(this); + + @override + String toString() => jsonEncode(toJson()); +} diff --git a/lib/src/model/ptz/preset_tour.g.dart b/lib/src/model/ptz/preset_tour.g.dart new file mode 100644 index 0000000..1ccfcd2 --- /dev/null +++ b/lib/src/model/ptz/preset_tour.g.dart @@ -0,0 +1,34 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'preset_tour.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +PresetTour _$PresetTourFromJson(Map json) => PresetTour( + token: json['@token'] as String, + name: json['Name'] as String?, + status: + PtzPresetTourStatus.fromJson(json['Status'] as Map), + autoStart: + OnvifUtil.mappedToBool(json['AutoStart'] as Map), + startingCondition: PtzPresetTourStartingCondition.fromJson( + json['StartingCondition'] as Map), + tourSpot: json['TourSpot'] == null + ? null + : PtzPresetTourSpot.fromJson( + json['TourSpot'] as Map), + extension: json['Extension'], + ); + +Map _$PresetTourToJson(PresetTour instance) => + { + '@token': instance.token, + 'Name': instance.name, + 'Status': instance.status, + 'AutoStart': instance.autoStart, + 'StartingCondition': instance.startingCondition, + 'TourSpot': instance.tourSpot, + 'Extension': instance.extension, + }; diff --git a/lib/src/model/ptz/ptz_preset_tour_spot.dart b/lib/src/model/ptz/ptz_preset_tour_spot.dart new file mode 100644 index 0000000..067cb2a --- /dev/null +++ b/lib/src/model/ptz/ptz_preset_tour_spot.dart @@ -0,0 +1,40 @@ +import 'dart:convert'; + +import 'package:easy_onvif/shared.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'ptz_preset_tour_spot.g.dart'; + +/// Indicates a tour spot currently staying. +@JsonSerializable() +class PtzPresetTourSpot { + /// Detail definition of preset position of the tour spot. + @JsonKey(name: 'PresetDetail') + final String presetDetail; + + /// Optional parameter to specify Pan/Tilt and Zoom speed on moving toward this tour spot. + @JsonKey(name: 'Speed') + final PtzSpeed? speed; + + /// Optional parameter to specify time duration of staying on this tour sport. + @JsonKey(name: 'StayTime') + final String? stayTime; + + @JsonKey(name: 'Extension') + final dynamic extension; + + PtzPresetTourSpot({ + required this.presetDetail, + this.speed, + this.stayTime, + this.extension, + }); + + factory PtzPresetTourSpot.fromJson(Map json) => + _$PtzPresetTourSpotFromJson(json); + + Map toJson() => _$PtzPresetTourSpotToJson(this); + + @override + String toString() => jsonEncode(toJson()); +} diff --git a/lib/src/model/ptz/ptz_preset_tour_spot.g.dart b/lib/src/model/ptz/ptz_preset_tour_spot.g.dart new file mode 100644 index 0000000..8154580 --- /dev/null +++ b/lib/src/model/ptz/ptz_preset_tour_spot.g.dart @@ -0,0 +1,25 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'ptz_preset_tour_spot.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +PtzPresetTourSpot _$PtzPresetTourSpotFromJson(Map json) => + PtzPresetTourSpot( + presetDetail: json['PresetDetail'] as String, + speed: json['Speed'] == null + ? null + : PtzSpeed.fromJson(json['Speed'] as Map), + stayTime: json['StayTime'] as String?, + extension: json['Extension'], + ); + +Map _$PtzPresetTourSpotToJson(PtzPresetTourSpot instance) => + { + 'PresetDetail': instance.presetDetail, + 'Speed': instance.speed, + 'StayTime': instance.stayTime, + 'Extension': instance.extension, + }; diff --git a/lib/src/model/ptz/ptz_preset_tour_starting_condition.dart b/lib/src/model/ptz/ptz_preset_tour_starting_condition.dart new file mode 100644 index 0000000..2db4392 --- /dev/null +++ b/lib/src/model/ptz/ptz_preset_tour_starting_condition.dart @@ -0,0 +1,61 @@ +import 'dart:convert'; + +import 'package:easy_onvif/util.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'ptz_preset_tour_starting_condition.g.dart'; + +enum PtzPresetTourDirection { + @JsonValue('Forward') + forward, + @JsonValue('Backward') + backward, + @JsonValue('Extended') + extended, +} + +/// Parameters to specify the detail behavior of the preset tour. +@JsonSerializable() +class PtzPresetTourStartingCondition { + /// Execute presets in random order. If set to true and Direction is also present, Direction will be ignored and presets of the Tour will be recalled randomly. + @JsonKey(name: 'RandomPresetOrder', fromJson: OnvifUtil.nullableMappedToBool) + final bool? randomPresetOrder; + + /// Optional parameter to specify how many times the preset tour is recurred. + @JsonKey(name: 'RecurringTime') + final int? recurringTime; + + /// Optional parameter to specify how long time duration the preset tour is recurred. + @JsonKey(name: 'RecurringDuration') + final String? recurringDuration; + + /// Optional parameter to choose which direction the preset tour goes. Forward shall be chosen in case it is omitted. + /// - enum { 'Forward', 'Backward', 'Extended' } + @JsonKey(name: 'Direction', fromJson: _fix) + final PtzPresetTourDirection? direction; + + @JsonKey(name: 'Extension') + final dynamic extension; + + PtzPresetTourStartingCondition({ + required this.randomPresetOrder, + this.recurringTime, + this.recurringDuration, + this.direction, + this.extension, + }); + + factory PtzPresetTourStartingCondition.fromJson(Map json) => + _$PtzPresetTourStartingConditionFromJson(json); + + Map toJson() => _$PtzPresetTourStartingConditionToJson(this); + + static PtzPresetTourDirection? _fix(Map? value) => + value == null + ? null + : $enumDecode( + _$PtzPresetTourDirectionEnumMap, OnvifUtil.mappedToString(value)); + + @override + String toString() => jsonEncode(toJson()); +} diff --git a/lib/src/model/ptz/ptz_preset_tour_starting_condition.g.dart b/lib/src/model/ptz/ptz_preset_tour_starting_condition.g.dart new file mode 100644 index 0000000..33c2b0b --- /dev/null +++ b/lib/src/model/ptz/ptz_preset_tour_starting_condition.g.dart @@ -0,0 +1,35 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'ptz_preset_tour_starting_condition.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +PtzPresetTourStartingCondition _$PtzPresetTourStartingConditionFromJson( + Map json) => + PtzPresetTourStartingCondition( + randomPresetOrder: OnvifUtil.nullableMappedToBool( + json['RandomPresetOrder'] as Map?), + recurringTime: json['RecurringTime'] as int?, + recurringDuration: json['RecurringDuration'] as String?, + direction: PtzPresetTourStartingCondition._fix( + json['Direction'] as Map?), + extension: json['Extension'], + ); + +Map _$PtzPresetTourStartingConditionToJson( + PtzPresetTourStartingCondition instance) => + { + 'RandomPresetOrder': instance.randomPresetOrder, + 'RecurringTime': instance.recurringTime, + 'RecurringDuration': instance.recurringDuration, + 'Direction': _$PtzPresetTourDirectionEnumMap[instance.direction], + 'Extension': instance.extension, + }; + +const _$PtzPresetTourDirectionEnumMap = { + PtzPresetTourDirection.forward: 'Forward', + PtzPresetTourDirection.backward: 'Backward', + PtzPresetTourDirection.extended: 'Extended', +}; diff --git a/lib/src/model/ptz/ptz_preset_tour_status.dart b/lib/src/model/ptz/ptz_preset_tour_status.dart new file mode 100644 index 0000000..eb98a85 --- /dev/null +++ b/lib/src/model/ptz/ptz_preset_tour_status.dart @@ -0,0 +1,54 @@ +import 'dart:convert'; + +import 'package:easy_onvif/util.dart'; +import 'package:json_annotation/json_annotation.dart'; + +import 'ptz_preset_tour_spot.dart'; + +part 'ptz_preset_tour_status.g.dart'; + +/// Indicates state of this preset tour by Idle/Touring/Paused. +/// - enum { 'Idle', 'Touring', 'Paused', 'Extended' } +enum PtzPresetTourState { + @JsonValue('Idle') + idle, + @JsonValue('Touring') + touring, + @JsonValue('Paused') + paused, + @JsonValue('Extended') + extended, +} + +/// Read only parameters to indicate the status of the preset tour. +@JsonSerializable() +class PtzPresetTourStatus { + /// Indicates state of this preset tour by Idle/Touring/Paused. + /// - enum { 'Idle', 'Touring', 'Paused', 'Extended' } + @JsonKey(name: 'State', fromJson: _fix) + final PtzPresetTourState state; + + /// Indicates a tour spot currently staying. + @JsonKey(name: 'CurrentTourSpot') + final PtzPresetTourSpot? currentTourSpot; + + @JsonKey(name: 'Extension') + final dynamic extension; + + PtzPresetTourStatus({ + required this.state, + this.currentTourSpot, + this.extension, + }); + + factory PtzPresetTourStatus.fromJson(Map json) => + _$PtzPresetTourStatusFromJson(json); + + Map toJson() => _$PtzPresetTourStatusToJson(this); + + static PtzPresetTourState _fix(Map value) => + $enumDecode(_$PtzPresetTourStateEnumMap, OnvifUtil.mappedToString(value)); + + @override + String toString() => jsonEncode(toJson()); +} diff --git a/lib/src/model/ptz/ptz_preset_tour_status.g.dart b/lib/src/model/ptz/ptz_preset_tour_status.g.dart new file mode 100644 index 0000000..3cffea3 --- /dev/null +++ b/lib/src/model/ptz/ptz_preset_tour_status.g.dart @@ -0,0 +1,32 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'ptz_preset_tour_status.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +PtzPresetTourStatus _$PtzPresetTourStatusFromJson(Map json) => + PtzPresetTourStatus( + state: PtzPresetTourStatus._fix(json['State'] as Map), + currentTourSpot: json['CurrentTourSpot'] == null + ? null + : PtzPresetTourSpot.fromJson( + json['CurrentTourSpot'] as Map), + extension: json['Extension'], + ); + +Map _$PtzPresetTourStatusToJson( + PtzPresetTourStatus instance) => + { + 'State': _$PtzPresetTourStateEnumMap[instance.state]!, + 'CurrentTourSpot': instance.currentTourSpot, + 'Extension': instance.extension, + }; + +const _$PtzPresetTourStateEnumMap = { + PtzPresetTourState.idle: 'Idle', + PtzPresetTourState.touring: 'Touring', + PtzPresetTourState.paused: 'Paused', + PtzPresetTourState.extended: 'Extended', +}; diff --git a/lib/src/ptz.dart b/lib/src/ptz.dart index d5aecce..9da6e62 100644 --- a/lib/src/ptz.dart +++ b/lib/src/ptz.dart @@ -216,6 +216,37 @@ class Ptz with UiLoggy { .sublist(0, limit); } + Future getPresetTour( + String profileToken, { + required String presetTourToken, + }) async { + loggy.debug('getPresetTour'); + + final envelope = await transport.sendRequest( + uri, + transport.securedEnvelope(soap.PtzRequest.getPresetTour( + profileToken, + presetTourToken: presetTourToken, + ))); + + if (envelope.body.response == null) throw Exception(); + + return GetPresetTourResponse.fromJson(envelope.body.response!).presetTour; + } + + Future> getPresetTours(String profileToken) async { + loggy.debug('getPresetTours'); + + final envelope = await transport.sendRequest( + uri, + transport + .securedEnvelope(soap.PtzRequest.getPresetTours(profileToken))); + + if (envelope.body.response == null) throw Exception(); + + return GetPresetToursResponse.fromJson(envelope.body.response!).presetTours; + } + Future> getPresetsMap(String profileToken) async { loggy.debug('getPresetsMap'); diff --git a/lib/src/soap/ptz.dart b/lib/src/soap/ptz.dart index eaeafa1..c6efbff 100644 --- a/lib/src/soap/ptz.dart +++ b/lib/src/soap/ptz.dart @@ -147,6 +147,38 @@ class PtzRequest { return Transport.builder.buildFragment(); } + /// XML for the [getPresetTour], requires a [profileToken] and [PresetTourToken] + static XmlDocumentFragment getPresetTour(String profileToken, + {required String presetTourToken}) { + Transport.builder.element('GetPresetTour', nest: () { + Transport.builder.namespace(Xmlns.tptz); + Transport.builder.element('ProfileToken', nest: () { + Transport.builder.namespace(Xmlns.tptz); + Transport.builder.text(profileToken); + }); + + Transport.builder.element('PresetTourToken', nest: () { + Transport.builder.namespace(Xmlns.tptz); + Transport.builder.text(presetTourToken); + }); + }); + + return Transport.builder.buildFragment(); + } + + /// XML for the [getPresetTours], requires a [profileToken] + static XmlDocumentFragment getPresetTours(String profileToken) { + Transport.builder.element('GetPresetTours', nest: () { + Transport.builder.namespace(Xmlns.tptz); + Transport.builder.element('ProfileToken', nest: () { + Transport.builder.namespace(Xmlns.tptz); + Transport.builder.text(profileToken); + }); + }); + + return Transport.builder.buildFragment(); + } + /// XML for the [getServiceCapabilities] static XmlDocumentFragment getServiceCapabilities() => Transport.quickTag('GetServiceCapabilities', Xmlns.tds); @@ -271,6 +303,25 @@ class PtzRequest { return Transport.builder.buildFragment(); } + /// XML for the [removePresetTour], requires a [profileToken] and [PresetTourToken] + static XmlDocumentFragment removePresetTour(String profileToken, + {required PresetTour presetTour}) { + Transport.builder.element('RemovePresetTour', nest: () { + Transport.builder.namespace(Xmlns.tptz); + Transport.builder.element('ProfileToken', nest: () { + Transport.builder.namespace(Xmlns.tptz); + Transport.builder.text(profileToken); + }); + + Transport.builder.element('PresetTourToken', nest: () { + Transport.builder.namespace(Xmlns.tptz); + Transport.builder.text(presetTour.token); + }); + }); + + return Transport.builder.buildFragment(); + } + /// XML for the [setHomePosition], requires a [profileToken] static XmlDocumentFragment setHomePosition(String profileToken) { Transport.builder.element('SetHomePosition', nest: () { diff --git a/pubspec.yaml b/pubspec.yaml index c331bf8..2bf6521 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: easy_onvif -version: 2.1.3+3 +version: 2.1.3+4 homepage: https://github.com/faithoflifedev/easy_onvif description: A pure Dart library designed primarily for command line automation of Onvif compatible devices, but can be used anywhere Dart is used. repository: https://github.com/faithoflifedev/easy_onvif.git @@ -9,7 +9,7 @@ environment: dependencies: args: ^2.4.2 crypto: ^3.0.3 - dio: ^5.3.3 + dio: ^5.4.0 ffi: ^2.1.0 html_unescape: ^2.0.0 intl: ^0.18.1 @@ -20,13 +20,13 @@ dependencies: shelf_router: ^1.1.4 sprintf: ^7.0.0 universal_io: ^2.2.2 - uuid: ^4.1.0 + uuid: ^4.2.1 xml: ^6.3.0 - xml2json: ^6.2.0 + xml2json: ^6.2.1 yaml: ^3.1.2 dev_dependencies: - build_runner: ^2.4.5 - grinder: ^0.9.4 + build_runner: ^2.4.7 + grinder: ^0.9.5 json_serializable: ^6.7.1 lints: ^3.0.0 mustache_template: ^2.0.0 @@ -34,6 +34,6 @@ dev_dependencies: pub_semver: ^2.1.4 publish_tools: ^0.1.0+12 pubspec: ^2.3.0 - test: ^1.24.8 + test: ^1.24.9 executables: onvif: diff --git a/tool/README.md b/tool/README.md index 633cce7..5ab09ad 100644 --- a/tool/README.md +++ b/tool/README.md @@ -260,6 +260,8 @@ Please see the cli documentation [README.md](https://github.com/faithoflifedev/e | GetConfigurationOptions | getConfigurationOptions | `Future` | [x\] | | GetConfigurations | getConfigurations | `Future>` | [x\] | | GetPresets | getPresets | `Future>` | [x\] | +| GetPresetTour | getPresetTour | `Future` | [ \] | +| GetPresetTours | getPresetTours | `Future>` | [ \] | | GetServiceCapabilities | getServiceCapabilities | `Future` | [x\] | | GetStatus | getStatus | `Future` | [x\] | | GotoHomePosition | gotoHomePosition | `Future` | [x\] | @@ -323,17 +325,17 @@ The values returned by the Onvif API `GetDeviceInformation` call. | Manufacturer | Model | Known Issue | | ------------------ | -------------- | -------------------------------- | | Happytimesoft | IPCamera | limited capabilities | -| D-Link Corporation | DCS-6511 | commands not implemented¹ | -| ONVIF | ENP1A14-IR/25X | commands not implemented² | +| ONVIF | ENP1A14-IR/25X | commands not implemented¹ | +| D-Link Corporation | DCS-6511 | commands not implemented² | | NONE | GX728MF-IR28 | commands not implemented³ | | LOREX | LNB4421SB | testing in progress | -¹ The following are not implemented for the ENP1A14-IR/25X: +¹ The ENP1A14-IR/25X does not support the following commands: * Recordings * `CreateRecording` * `DeleteRecording` -² The following are not implemented for the DCS-6511: +² The DCS-6511 does not support the following commands: * Device Management: * `GetServices` * `GetServiceCapabilities` @@ -346,7 +348,7 @@ The values returned by the Onvif API `GetDeviceInformation` call. * PTZ: * not tested -³ The following are not implemented for the GX728MF-IR28: +³ The GX728MF-IR28 does not support the following commands: * Device Management: * `GetSystemUris` * Media1: diff --git a/tool/config.sample.yaml b/tool/config.sample.yaml deleted file mode 100644 index a334069..0000000 --- a/tool/config.sample.yaml +++ /dev/null @@ -1,24 +0,0 @@ -repo: faithoflifedev/easy_onvif - -pkg: - githubBearerToken: [access token] - humanName: easy_onvif - botName: FLN Developer - botEmail: faithoflifedev@gmail.com - executables: - obs: bin/onvif.dart - homebrewRepo: faithoflifedev/homebrew-easy_onvif - # homebrewFormula: Formula/obs.rb - -meta: lib/src/util/meta.dart - -templates: - - name: README.md - type: overwrite - - name: CHANGELOG.md - type: prepend - -commit: more config requests, tests and improved build tools -change: | - * updated build tools - * dependency bump diff --git a/tool/reddit_post.md b/tool/reddit_post.md deleted file mode 100644 index f669b2c..0000000 --- a/tool/reddit_post.md +++ /dev/null @@ -1,18 +0,0 @@ -new release for google_vision, integrates Google Vision features into Dart and the command line - -Hello Dart developers, - -Announcing the new release of **google\_vision** {{ pubspec.version }}! - -A native [Dart](https://dart.dev/) package that integrates Google Vision features, including: - -* image labeling, -* face, logo, and landmark detection, -* optical character recognition (OCR), -* detection of explicit content - -The v1.0.x also includes a **cli** interface. Check out the [README.md](https://github.com/faithoflifedev/google_vision/blob/main/bin/README.md) for instructions on how to use the new cli tool to use any supported commands directly from the command line. Now you can use the power of Google Vision in a shell script. - -[https://pub.dev/packages/google\_vision](https://pub.dev/packages/google_vision) - -[https://github.com/faithoflifedev/google\_vision](https://github.com/faithoflifedev/google_vision) \ No newline at end of file