PyAres 0.2.0__tar.gz → 0.2.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. pyares-0.2.2/.github/dependabot.yml +15 -0
  2. pyares-0.2.2/.github/workflows/pypi.yaml +59 -0
  3. pyares-0.2.2/.github/workflows/python-tests.yaml +40 -0
  4. pyares-0.2.2/.gitignore +167 -0
  5. pyares-0.2.2/PKG-INFO +168 -0
  6. {pyares-0.2.0 → pyares-0.2.2}/PyAres/Analyzing/analysis_service.py +6 -5
  7. {pyares-0.2.0 → pyares-0.2.2}/PyAres/Device/device_service.py +9 -8
  8. {pyares-0.2.0 → pyares-0.2.2}/PyAres/Planning/planner_models.py +1 -1
  9. {pyares-0.2.0 → pyares-0.2.2}/PyAres/Planning/planning_service.py +3 -3
  10. {pyares-0.2.0 → pyares-0.2.2}/PyAres/Utils/ares_data_type_utils.py +3 -2
  11. {pyares-0.2.0 → pyares-0.2.2}/PyAres/Utils/ares_outcome_utils.py +3 -1
  12. pyares-0.2.2/poetry.lock +188 -0
  13. pyares-0.2.2/pyproject.toml +32 -0
  14. pyares-0.2.2/setup.cfg +0 -0
  15. pyares-0.2.2/tests/__init__.py +0 -0
  16. pyares-0.2.2/tests/mock_grpc_context.py +15 -0
  17. pyares-0.2.2/tests/test_analyzer.py +162 -0
  18. pyares-0.2.2/tests/test_ares_device.py +170 -0
  19. pyares-0.2.2/tests/test_planner.py +139 -0
  20. pyares-0.2.0/PKG-INFO +0 -13
  21. pyares-0.2.0/PyAres.egg-info/PKG-INFO +0 -13
  22. pyares-0.2.0/PyAres.egg-info/SOURCES.txt +0 -45
  23. pyares-0.2.0/PyAres.egg-info/dependency_links.txt +0 -1
  24. pyares-0.2.0/PyAres.egg-info/requires.txt +0 -3
  25. pyares-0.2.0/PyAres.egg-info/top_level.txt +0 -1
  26. pyares-0.2.0/pyproject.toml +0 -27
  27. pyares-0.2.0/setup.cfg +0 -4
  28. {pyares-0.2.0 → pyares-0.2.2}/LICENSE +0 -0
  29. {pyares-0.2.0 → pyares-0.2.2}/PyAres/Analyzing/__init__.py +0 -0
  30. {pyares-0.2.0 → pyares-0.2.2}/PyAres/Analyzing/analyzer_models.py +0 -0
  31. {pyares-0.2.0 → pyares-0.2.2}/PyAres/Demo/analyzer_test.py +0 -0
  32. {pyares-0.2.0 → pyares-0.2.2}/PyAres/Demo/analyzer_test_tools_demo.py +0 -0
  33. {pyares-0.2.0 → pyares-0.2.2}/PyAres/Demo/analyzer_wiki.py +0 -0
  34. {pyares-0.2.0 → pyares-0.2.2}/PyAres/Demo/device_test.py +0 -0
  35. {pyares-0.2.0 → pyares-0.2.2}/PyAres/Demo/hotplate.py +0 -0
  36. {pyares-0.2.0 → pyares-0.2.2}/PyAres/Demo/planner_test.py +0 -0
  37. {pyares-0.2.0 → pyares-0.2.2}/PyAres/Demo/planner_test_tools_demo.py +0 -0
  38. {pyares-0.2.0 → pyares-0.2.2}/PyAres/Demo/planner_wiki.py +0 -0
  39. {pyares-0.2.0 → pyares-0.2.2}/PyAres/Demo/rotary_mixer.py +0 -0
  40. {pyares-0.2.0 → pyares-0.2.2}/PyAres/Device/__init__.py +0 -0
  41. {pyares-0.2.0 → pyares-0.2.2}/PyAres/Device/device_models.py +0 -0
  42. {pyares-0.2.0 → pyares-0.2.2}/PyAres/Device/device_warnings.py +0 -0
  43. {pyares-0.2.0 → pyares-0.2.2}/PyAres/Models/__init__.py +0 -0
  44. {pyares-0.2.0 → pyares-0.2.2}/PyAres/Models/ares_data_models.py +0 -0
  45. {pyares-0.2.0 → pyares-0.2.2}/PyAres/Planning/__init__.py +0 -0
  46. {pyares-0.2.0 → pyares-0.2.2}/PyAres/Utils/ares_data_schema_utils.py +0 -0
  47. {pyares-0.2.0 → pyares-0.2.2}/PyAres/Utils/ares_device_command_utils.py +0 -0
  48. {pyares-0.2.0 → pyares-0.2.2}/PyAres/Utils/ares_struct_utils.py +0 -0
  49. {pyares-0.2.0 → pyares-0.2.2}/PyAres/Utils/ares_value_utils.py +0 -0
  50. {pyares-0.2.0 → pyares-0.2.2}/PyAres/Utils/param_history_info_utils.py +0 -0
  51. {pyares-0.2.0 → pyares-0.2.2}/PyAres/Utils/plan_request_utils.py +0 -0
  52. {pyares-0.2.0 → pyares-0.2.2}/PyAres/Utils/plan_response_utils.py +0 -0
  53. {pyares-0.2.0 → pyares-0.2.2}/PyAres/Utils/planning_param_utils.py +0 -0
  54. {pyares-0.2.0 → pyares-0.2.2}/PyAres/__init__.py +0 -0
  55. {pyares-0.2.0 → pyares-0.2.2}/PyAres/test_tools/__init__.py +0 -0
  56. {pyares-0.2.0 → pyares-0.2.2}/PyAres/test_tools/analyzer_tester.py +0 -0
  57. {pyares-0.2.0 → pyares-0.2.2}/PyAres/test_tools/planner_tester.py +0 -0
  58. {pyares-0.2.0 → pyares-0.2.2}/README.md +0 -0
  59. {pyares-0.2.0 → pyares-0.2.2}/setup.py +0 -0
@@ -0,0 +1,15 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: "pip"
4
+ directory: "/"
5
+ schedule:
6
+ interval: "daily"
7
+ ignore:
8
+ - dependency-name: "pyares"
9
+ - package-ecosystem: "github-actions"
10
+ directory: /
11
+ schedule:
12
+ interval: "weekly"
13
+ groups:
14
+ github-actions:
15
+ patterns: ["*"]
@@ -0,0 +1,59 @@
1
+ name: Upload PyARES Python Package
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ permissions:
8
+ contents: read
9
+
10
+ jobs:
11
+ release-build:
12
+ name: Build and Publish Python Distributions to PyPi
13
+ runs-on: ubuntu-latest
14
+ defaults:
15
+ run:
16
+ working-directory: .
17
+
18
+ steps:
19
+ - uses: actions/checkout@v6
20
+ - name: Setup Python
21
+ uses: actions/setup-python@v6
22
+ with:
23
+ python-version: "3.10"
24
+ - name: Set PyARES Package Name From Tag
25
+ run: echo "PYARES_PACKAGE_VERSION=${GITHUB_REF/refs\/tags\/v/}" >> $GITHUB_ENV
26
+ - name: Build Package
27
+ run: |
28
+ python -m pip install build
29
+ python -m build
30
+ - name: Upload Distribution
31
+ uses: actions/upload-artifact@v6
32
+ with:
33
+ name: pyares-release-dists
34
+ path: dist/
35
+ if-no-files-found: error
36
+
37
+ pypi-publish:
38
+ runs-on: ubuntu-latest
39
+ needs:
40
+ - release-build
41
+ permissions:
42
+ id-token: write
43
+ environment:
44
+ name: pypi
45
+ url: https://pypi.org/p/pyares
46
+
47
+ steps:
48
+ - name: Retrieve Release Distributions
49
+ uses: actions/download-artifact@v7
50
+ with:
51
+ name: pyares-release-dists
52
+ path: dist/
53
+ - name: Publish Package
54
+ uses: pypa/gh-action-pypi-publish@release/v1
55
+ with:
56
+ packages-dir: dist/
57
+ user: __token__
58
+ password: ${{ secrets.PYPI_API_TOKEN }}
59
+
@@ -0,0 +1,40 @@
1
+ name: PyAres Unit Tests
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - Develop
7
+ pull_request:
8
+ branches:
9
+ - Develop
10
+
11
+ jobs:
12
+ build-and-test:
13
+ runs-on: ubuntu-latest
14
+
15
+ # Optional: Test across multiple Python versions to ensure compatibility
16
+ strategy:
17
+ matrix:
18
+ python-version: ["3.10"]
19
+
20
+ steps:
21
+ - uses: actions/checkout@v6
22
+
23
+ - name: Set up Python ${{ matrix.python-version }}
24
+ uses: actions/setup-python@v6
25
+ with:
26
+ python-version: ${{ matrix.python-version }}
27
+
28
+ - name: Install Dependencies
29
+ env:
30
+ PYARES_PACKAGE_VERSION: "0.0.1"
31
+ run: |
32
+ python -m pip install --upgrade pip
33
+ pip install -e .
34
+ pip install grpcio grpcio-tools protobuf pytest
35
+
36
+ - name: Run Tests
37
+ run: |
38
+ # This discovers all files starting with 'test_' in the 'tests' directory
39
+ # and runs them.
40
+ pytest -v tests/
@@ -0,0 +1,167 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py,cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+ cover/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ .pybuilder/
76
+ target/
77
+
78
+ # Jupyter Notebook
79
+ .ipynb_checkpoints
80
+
81
+ # IPython
82
+ profile_default/
83
+ ipython_config.py
84
+
85
+ # pyenv
86
+ # For a library or package, you might want to ignore these files since the code is
87
+ # intended to run in multiple environments; otherwise, check them in:
88
+ # .python-version
89
+
90
+ # pipenv
91
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
+ # install all needed dependencies.
95
+ #Pipfile.lock
96
+
97
+ # UV
98
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
99
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
100
+ # commonly ignored for libraries.
101
+ #uv.lock
102
+
103
+ # poetry
104
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
105
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
106
+ # commonly ignored for libraries.
107
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
108
+ #poetry.lock
109
+
110
+ # pdm
111
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
112
+ #pdm.lock
113
+ # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
114
+ # in version control.
115
+ # https://pdm.fming.dev/latest/usage/project/#working-with-version-control
116
+ .pdm.toml
117
+ .pdm-python
118
+ .pdm-build/
119
+
120
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
121
+ __pypackages__/
122
+
123
+ # Celery stuff
124
+ celerybeat-schedule
125
+ celerybeat.pid
126
+
127
+ # SageMath parsed files
128
+ *.sage.py
129
+
130
+ # Environments
131
+ .env
132
+ .venv
133
+ env/
134
+ venv/
135
+ ENV/
136
+ env.bak/
137
+ venv.bak/
138
+
139
+ # Spyder project settings
140
+ .spyderproject
141
+ .spyproject
142
+
143
+ # Rope project settings
144
+ .ropeproject
145
+
146
+ # mkdocs documentation
147
+ /site
148
+
149
+ # mypy
150
+ .mypy_cache/
151
+ .dmypy.json
152
+ dmypy.json
153
+
154
+ # Pyre type checker
155
+ .pyre/
156
+
157
+ # pytype static type analyzer
158
+ .pytype/
159
+
160
+ # Cython debug symbols
161
+ cython_debug/
162
+
163
+ # Ruff stuff:
164
+ .ruff_cache/
165
+
166
+ # PyPI configuration file
167
+ .pypirc
pyares-0.2.2/PKG-INFO ADDED
@@ -0,0 +1,168 @@
1
+ Metadata-Version: 2.4
2
+ Name: PyAres
3
+ Version: 0.2.2
4
+ Summary: The official Python library for ARES.
5
+ Project-URL: Homepage, https://github.com/AFRL-ARES
6
+ Author-email: AFRL <AFRL.RX.AREScontact@us.af.mil>
7
+ License: MIT
8
+ License-File: LICENSE
9
+ Classifier: Operating System :: OS Independent
10
+ Classifier: Programming Language :: Python :: 3
11
+ Requires-Python: >=3.10
12
+ Requires-Dist: ares-datamodel>=0.15.1b1
13
+ Requires-Dist: grpcio-tools>=1.75.1
14
+ Requires-Dist: grpcio<2.0.0,>=1.71.0
15
+ Description-Content-Type: text/markdown
16
+
17
+ # PyAres
18
+ The PyAres library is designed to provide support for building planners, analyzers and devices as part of your ARES self driving labratory. PyAres leverages the power of protobuf and gRPC to communicate with your ARES system while providing a simple Pythonic API.
19
+
20
+ ### ✨ Features
21
+ * A Pythonic API built on the performance of Protobuf and gRPC to streamline the creation of self-driving lab components
22
+ * Easily define custom decision-making processes with your own PyAres Planners
23
+ * Integrate custom data processing and intepretation workflows with PyAres Analyzers
24
+ * Connect and control new hardware, making your implementations ARES ready as a PyAres Device
25
+
26
+ ### 🏗️ Installation
27
+
28
+ PyAres can be installed using pip:
29
+ ```console
30
+ pip install PyAres
31
+ ```
32
+
33
+ ### 🧠 Planner Usage
34
+
35
+ Planners can be initialized using the AresPlannerService class. Below is a basic example of setting up a planner.
36
+
37
+ ``` Python
38
+ from PyAres import AresPlannerService
39
+ from PyAres import PlanRequest
40
+ from PyAres import PlanResponse
41
+ from PyAres import AresDataType
42
+
43
+ import random
44
+
45
+ def plan(request: PlanRequest) -> PlanResponse:
46
+ #This is where your custom planning logic goes
47
+ planned_values = []
48
+ names = []
49
+
50
+ for param in request.parameters:
51
+ planned_values.append(random.uniform(param.minimum_value, param.maximum_value))
52
+ names.append(param.name)
53
+
54
+ return PlanResponse(parameter_names=names, parameter_values=planned_values)
55
+
56
+
57
+ if __name__ == "__main__":
58
+ #Basic details about your planner
59
+ name = "Demo Planner"
60
+ version = "1.0.0"
61
+ description = "This is a test planner to demonstrate working with PyAres to create planners!"
62
+ pythonDemoPlanner = AresPlannerService(plan, name, description, version)
63
+
64
+ #Add Supported Types
65
+ pythonDemoPlanner.add_supported_type(AresDataType.NUMBER)
66
+ ```
67
+ This example creates a simple planner called "Demo Planner", that supports planning for numeric values. The 'plan' method shown here is where our custom planning logic lives. For this example, we generate a random number between the minimum and maximum value of each provided parameter.
68
+
69
+ ### 🔍 Analyzer Usage
70
+
71
+ Analyzers can be initialized using the AresAnalyzerService class. Below is a basic example of setting up an analyzer.
72
+
73
+ ```Python
74
+ from PyAres import AresAnalyzerService
75
+ from PyAres import AnalysisRequest
76
+ from PyAres import Analysis
77
+ from PyAres import AresDataType
78
+
79
+ def analyze(request: AnalysisRequest) -> Analysis:
80
+ #Custom Analysis Logic
81
+ growth = request.inputs.get("Growth")
82
+ temperature = request.inputs.get("Temperature")
83
+
84
+ print(f"Growth: {growth}")
85
+ print(f"Temperature: {temperature}")
86
+
87
+ analysis = Analysis(result=growth, success=True)
88
+ return analysis
89
+
90
+
91
+ if __name__ == "__main__":
92
+ #Basic details about your analyzer
93
+ name = "Python Test Analyzer"
94
+ version = "0.0.1"
95
+ description = "This is a test analyzer to demonstrate working with PyAres to create analyzers!"
96
+ pythonDemoAnalyzer = AresAnalyzerService(analyze, name, version, description)
97
+
98
+ #Add Analysis Parameters
99
+ pythonDemoAnalyzer.add_analysis_parameter("Growth", AresDataType.NUMBER)
100
+ pythonDemoAnalyzer.add_analysis_parameter("Temperature", AresDataType.NUMBER)
101
+
102
+ pythonDemoAnalyzer.start()
103
+ ```
104
+ This example creates a simple analyzer that expects to receive two values from ARES, growth and temperature. It then returns a simple static value of six as the analysis result.
105
+
106
+ ### 💻 Device Usage
107
+
108
+ PyAres gives you the ability to create devices to communicate with your ARES system. Typically your device would be external hardware connected via serial port or USB to your computer. For demonstration purposes, below is a simulated device that has a modifiable temperature value. It's temperature can be set with the set_temperature method, or retrieved with the get_temperature method. We use a five second delay in the set_temperature method to simulate a delayed response from hardward. It also implements the get_device_state method which returns any data ARES should log as this devices state, and enter_safe_mode to fulfill the required ability for ARES to be able to reset any device to a known state.
109
+
110
+ ```Python
111
+ class DemoDevice:
112
+ # A simulated device. In reality, these communications would be happening with external hardware over serial, usb, etc.
113
+ def __init__(self):
114
+ self.temperature = 0.0
115
+
116
+ def set_temperature(self, temperature: float):
117
+ self.temperature = temperature
118
+ time.sleep(5)
119
+ return {}
120
+
121
+ def get_temperature(self):
122
+ # Dictionary key should match what we defined in our schema earlier
123
+ return { "temperature": self.temperature }
124
+
125
+ def get_device_state(self):
126
+ state_dictionary = { "temperature": self.temperature }
127
+ return state_dictionary
128
+
129
+ def enter_safe_mode(self):
130
+ self.temperature = 0
131
+ ```
132
+
133
+ PyAres can be used to connect this simulated device with ARES. Below is a basic example of setting up a PyAres device.
134
+
135
+ ```Python
136
+ device = DemoDevice()
137
+
138
+ if __name__ == "__main__":
139
+ # Basic information about my device
140
+ device_name = "Demo Device"
141
+ description = "A device to demonstrate the PyAres device capabilities"
142
+ version = "1.0.0"
143
+ device_service = AresDeviceService(device.enter_safe_mode, device.get_device_state, device_name, description, version)
144
+
145
+ #Create Command Descriptor, then add command
146
+ parameter_schema = DeviceSchemaEntry(AresDataType.NUMBER, "A numeric temperature value", "Degree's Celsius")
147
+ input_schema = { "temperature": parameter_schema }
148
+ descriptor = DeviceCommandDescriptor("Set Temperature", "Set's the temperature of the demo device to the provided value.", input_schema, {})
149
+ device_service.add_new_command(descriptor, device.set_temperature)
150
+
151
+ output_schema = {"temperature": DeviceSchemaEntry(AresDataType.NUMBER, "The current temperature of the device", "Degree's Celsius")}
152
+ get_temp_desc = DeviceCommandDescriptor("Get Temperature", "Get's the current temperature of the demo device.", {}, output_schema)
153
+ device_service.add_new_command(get_temp_desc, device.get_temperature)
154
+
155
+ #Add Settings
156
+ device_service.add_setting("Allow Negative Values", True)
157
+
158
+ device_service.start()
159
+ ```
160
+ The central component to your PyAres device is your AresDeviceService. This class acts as a bridge, managing all gRPC communications between PyAres and ARES, and provides the ability to define the behavior and capabilities of your device. Here we create a device with two commands; "Get Temperature" and "Set Temperature". To define commands in PyAres, you must provide a defined schema for both the input and output of the command in the form of a dictionary. This gives the PyAres user a flexible way to represent the data that your commands expect to receive, as well as the data ARES should expect to come from your commands. This information becomes part of your DeviceCommandDescriptor, which also holds a name for your command as well as a brief description. We then report our command capabilities to ARES via the add_new_command method. This method takes in our descriptor, and a reference to the method you defined for your command.
161
+
162
+ ### 📄 License
163
+
164
+ The PyAres project is licensed under the MIT License - see details in [LICENSE.txt]([https://github.com/AFRL-ARES/PyAres/blob/Develop/LICENSE.txt](https://github.com/AFRL-ARES/PyAres/blob/Develop/LICENSE)) <br></br>
165
+
166
+ ### CLEARANCE
167
+ Distribution A. Approved for public release: distribution unlimited. AFRL-2025-5332.
168
+
@@ -145,13 +145,14 @@ class AresAnalyzerServiceWrapper(analyzer_service_grpc.AresRemoteAnalyzerService
145
145
  def ValidateInputs(self, request: analyzer_service.ParameterValidationRequest, context):
146
146
  print("Validating Inputs")
147
147
  response = analyzer_service.ParameterValidationResult(success=True)
148
- provided_params: Mapping[str, ares_data_type_pb2.AresDataType] = request.input_schema.fields
148
+ provided_params: Mapping[str, ares_data_schema_pb2.SchemaEntry] = request.input_schema.fields
149
149
 
150
150
  for stored_key, stored_schema in self._analysis_parameters.items():
151
+ print(f"LOOKING AT {stored_key}")
151
152
  if stored_key in provided_params:
152
- matching_schema = provided_params.get(stored_key)
153
-
154
- if stored_schema.type != matching_schema:
153
+ matching_schema = provided_params[stored_key]
154
+ if stored_schema.type != matching_schema.type:
155
+ print(f" THIS IS THE TYPE RIGHT HERE LOOK AT IT: {type(matching_schema)}")
155
156
  message = f"Schema Mismatch! {stored_key} was provided with the value type {stored_schema.type}, but the value type {matching_schema} was expected!"
156
157
  response.messages.append(message)
157
158
  print(message)
@@ -161,7 +162,7 @@ class AresAnalyzerServiceWrapper(analyzer_service_grpc.AresRemoteAnalyzerService
161
162
  response.messages.append(message)
162
163
  print(message)
163
164
 
164
- if response.messages.count != 0:
165
+ if len(response.messages) != 0:
165
166
  response.success = False
166
167
 
167
168
  return response
@@ -128,8 +128,7 @@ class AresDeviceServiceWrapper(device_service_grpc.AresRemoteDeviceServiceServic
128
128
  try:
129
129
  for key, value in self._current_settings.items():
130
130
  new_entry = response.settings.fields[key]
131
- new_ares_value = ares_value_utils.create_ares_value(value)
132
- new_entry.CopyFrom(new_ares_value)
131
+ new_entry.CopyFrom(value)
133
132
 
134
133
  return response
135
134
 
@@ -138,7 +137,10 @@ class AresDeviceServiceWrapper(device_service_grpc.AresRemoteDeviceServiceServic
138
137
  return response
139
138
 
140
139
  def SetSettings(self, request: device_service.SetSettingsRequest, context) -> empty_pb2.Empty:
141
- self._current_settings = ares_struct_utils.ares_struct_to_dict(request.settings)
140
+ for key, value in request.settings.fields.items():
141
+ if key in self._current_settings:
142
+ self._current_settings[key] = value
143
+
142
144
  return empty_pb2.Empty()
143
145
 
144
146
  def GetStateSchema(self, request, context) -> device_service.StateSchemaResponse:
@@ -181,6 +183,10 @@ class AresDeviceServiceWrapper(device_service_grpc.AresRemoteDeviceServiceServic
181
183
  if polling_info.polling_type == device_polling_settings_pb2.PollingType.INTERVAL:
182
184
  delay = polling_info.interval_ms/1000
183
185
  while True:
186
+ if context.is_active() == False:
187
+ print("Client for ARES device has disconnected.")
188
+ break
189
+
184
190
  response = self._update_device_state()
185
191
  if isinstance(response, Awaitable):
186
192
  response = response.__await__()
@@ -195,11 +201,6 @@ class AresDeviceServiceWrapper(device_service_grpc.AresRemoteDeviceServiceServic
195
201
  ares_struct_utils.add_value_to_struct(proto_response.state, key, ares_value_utils.create_ares_value(value))
196
202
 
197
203
  yield proto_response
198
-
199
- if context.is_active() == False:
200
- print("Client for ARES device has disconnected.")
201
- break
202
-
203
204
  time.sleep(delay)
204
205
 
205
206
  else:
@@ -41,7 +41,7 @@ class PlanningParameter:
41
41
  self.name: str = name
42
42
  self.minimum_value: float = minimum_value
43
43
  self.maximum_value: float = maximum_value
44
- self.param_history: List = param_history
44
+ self.param_history: List[ParameterHistoryItem] = param_history
45
45
  self.data_type: AresDataType = data_type
46
46
  self.is_planned: bool = is_planned
47
47
  self.is_result: bool = is_result
@@ -56,7 +56,7 @@ class AresPlannerServiceWrapper(planner_service_grpc.AresRemotePlannerServiceSer
56
56
  for(key, value) in self._settings.items():
57
57
  settings_entry: ares_data_schema_pb2.SchemaEntry = capabilities.settings_schema.fields[key]
58
58
  settings_entry.type = value.type
59
- settings_entry.optional - value.optional
59
+ settings_entry.optional = value.optional
60
60
 
61
61
  if len(value.string_choices.strings) != 0:
62
62
  settings_entry.string_choices.strings.extend(value.string_choices.strings)
@@ -258,7 +258,7 @@ class AresPlannerService:
258
258
  Setting this value to false will allow you to continue execution after starting your service, however this should ONLY be done if you have
259
259
  another mechanism for keeping your process alive (such as a GUI, or a loop). Defaults to true.
260
260
  """
261
- print(f"Starting Ares Device Service on port {self._port}...")
261
+ print(f"Starting Ares Planning Service on port {self._port}...")
262
262
  self._server.start()
263
263
 
264
264
  if wait_for_termination:
@@ -269,4 +269,4 @@ class AresPlannerService:
269
269
  Stops the service, terminating the connection.
270
270
  """
271
271
  print("Stopping Ares Planning Service...")
272
- self._server.stop(0).wait()
272
+ self._server.stop(0).wait()
@@ -1,10 +1,11 @@
1
- from typing import Union
1
+ from typing import Union, cast
2
2
  from ares_datamodel import ares_data_type_pb2
3
3
  from ..Models import AresDataType
4
4
 
5
5
  def python_ares_type_to_proto_ares_type(py_value: AresDataType) -> ares_data_type_pb2.AresDataType:
6
6
  """ A method to convert from the python AresDataType class to the protobuf version """
7
- return ares_data_type_pb2.AresDataType(py_value.value)
7
+ val = cast(ares_data_type_pb2.AresDataType, py_value.value)
8
+ return val
8
9
 
9
10
  def proto_ares_type_to_python_ares_type(proto_value: ares_data_type_pb2.AresDataType) -> AresDataType:
10
11
  """ A method to convert from the protobuf AresDataType class to the python version """
@@ -1,9 +1,11 @@
1
1
  from ..Models import Outcome
2
2
  from ares_datamodel import ares_outcome_enum_pb2
3
+ from typing import cast
3
4
 
4
5
  def python_ares_outcome_to_proto_ares_outcome(py_value: Outcome) -> ares_outcome_enum_pb2.Outcome:
5
6
  """ A method to convert from the python AresDataType class to the protobuf version """
6
- return ares_outcome_enum_pb2.Outcome(py_value.value)
7
+ val = cast(ares_outcome_enum_pb2.Outcome, py_value.value)
8
+ return val
7
9
 
8
10
  def proto_ares_outcome_to_python_ares_outcome(proto_value: ares_outcome_enum_pb2.Outcome) -> Outcome:
9
11
  """ A method to convert from the protobuf AresDataType class to the python version """