deebot-client 3.0.3.dev0__tar.gz → 4.0.0__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 (154) hide show
  1. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/.devcontainer.json +4 -0
  2. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/.github/ISSUE_TEMPLATE/bug_report.yml +1 -1
  3. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/.github/workflows/ci.yml +2 -2
  4. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/.github/workflows/python-publish.yml +1 -1
  5. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/.pre-commit-config.yaml +8 -11
  6. {deebot-client-3.0.3.dev0/deebot_client.egg-info → deebot-client-4.0.0}/PKG-INFO +4 -4
  7. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/README.md +3 -3
  8. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/api_client.py +5 -7
  9. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/authentication.py +9 -9
  10. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/capabilities.py +8 -3
  11. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/command.py +71 -7
  12. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/commands/json/__init__.py +15 -2
  13. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/commands/json/battery.py +3 -3
  14. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/commands/json/charge.py +3 -3
  15. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/commands/json/charge_state.py +8 -8
  16. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/commands/json/clean.py +12 -13
  17. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/commands/json/clean_count.py +5 -5
  18. deebot-client-4.0.0/deebot_client/commands/json/common.py +105 -0
  19. deebot-client-4.0.0/deebot_client/commands/json/efficiency.py +40 -0
  20. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/commands/json/error.py +5 -4
  21. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/commands/json/fan_speed.py +5 -4
  22. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/commands/json/life_span.py +4 -3
  23. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/commands/json/map.py +39 -37
  24. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/commands/json/network.py +2 -3
  25. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/commands/json/pos.py +7 -5
  26. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/commands/json/stats.py +3 -3
  27. deebot-client-4.0.0/deebot_client/commands/json/voice_assistant_state.py +19 -0
  28. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/commands/json/volume.py +10 -8
  29. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/commands/json/water_info.py +13 -8
  30. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/commands/json/work_mode.py +5 -4
  31. deebot-client-4.0.0/deebot_client/commands/xml/__init__.py +1 -0
  32. deebot-client-3.0.3.dev0/deebot_client/vacuum_bot.py → deebot-client-4.0.0/deebot_client/device.py +16 -14
  33. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/event_bus.py +7 -7
  34. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/events/__init__.py +12 -3
  35. deebot-client-4.0.0/deebot_client/events/efficiency_mode.py +20 -0
  36. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/events/map.py +3 -4
  37. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/events/water_info.py +3 -3
  38. deebot-client-4.0.0/deebot_client/hardware/deebot/85nbtp.py +193 -0
  39. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/hardware/deebot/fallback.py +3 -1
  40. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/hardware/deebot/p1jij8.py +3 -1
  41. deebot-client-4.0.0/deebot_client/hardware/deebot/p95mgv.py +220 -0
  42. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/hardware/deebot/vi829v.py +3 -1
  43. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/hardware/deebot/yna5xi.py +3 -1
  44. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/logging_filter.py +4 -4
  45. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/map.py +7 -6
  46. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/models.py +11 -8
  47. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/mqtt_client.py +9 -7
  48. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/util.py +15 -10
  49. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0/deebot_client.egg-info}/PKG-INFO +4 -4
  50. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client.egg-info/SOURCES.txt +11 -2
  51. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/pyproject.toml +24 -46
  52. deebot-client-4.0.0/requirements-test.txt +12 -0
  53. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/tests/commands/json/__init__.py +34 -6
  54. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/tests/commands/json/test_advanced_mode.py +5 -3
  55. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/tests/commands/json/test_carpet.py +3 -3
  56. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/tests/commands/json/test_charge.py +6 -4
  57. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/tests/commands/json/test_clean.py +10 -10
  58. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/tests/commands/json/test_clean_log.py +5 -1
  59. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/tests/commands/json/test_clean_preference.py +3 -3
  60. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/tests/commands/json/test_common.py +12 -13
  61. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/tests/commands/json/test_continuous_cleaning.py +3 -3
  62. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/tests/commands/json/test_custom.py +10 -4
  63. deebot-client-4.0.0/tests/commands/json/test_efficiency.py +40 -0
  64. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/tests/commands/json/test_life_span.py +29 -6
  65. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/tests/commands/json/test_map.py +22 -23
  66. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/tests/commands/json/test_mulitmap_state.py +5 -3
  67. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/tests/commands/json/test_true_detect.py +5 -3
  68. deebot-client-4.0.0/tests/commands/json/test_voice_assistant_state.py +22 -0
  69. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/tests/commands/json/test_water_info.py +10 -4
  70. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/tests/conftest.py +0 -12
  71. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/tests/fixtures/base.py +11 -7
  72. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/tests/hardware/test_init.py +48 -2
  73. deebot-client-4.0.0/tests/messages/json/__init__.py +0 -0
  74. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/tests/messages/test_messages.py +2 -2
  75. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/tests/test_authentication.py +1 -1
  76. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/tests/test_command.py +5 -2
  77. deebot-client-3.0.3.dev0/tests/test_vacuum_bot.py → deebot-client-4.0.0/tests/test_device.py +7 -7
  78. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/tests/test_event_bus.py +38 -26
  79. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/tests/test_mqtt_client.py +50 -17
  80. deebot-client-3.0.3.dev0/deebot_client/commands/json/common.py +0 -151
  81. deebot-client-3.0.3.dev0/requirements-test.txt +0 -13
  82. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/.codecov.yml +0 -0
  83. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/.coveragerc +0 -0
  84. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/.gitattributes +0 -0
  85. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/.github/FUNDING.yml +0 -0
  86. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  87. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/.github/dependabot.yml +0 -0
  88. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/.github/release-drafter.yml +0 -0
  89. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/.github/workflows/codeql-analysis.yml +0 -0
  90. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/.github/workflows/release-drafter.yml +0 -0
  91. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/.gitignore +0 -0
  92. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/.prettierrc.js +0 -0
  93. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/.yamllint +0 -0
  94. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/LICENSE.txt +0 -0
  95. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/__init__.py +0 -0
  96. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/commands/__init__.py +0 -0
  97. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/commands/json/advanced_mode.py +0 -0
  98. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/commands/json/carpet.py +0 -0
  99. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/commands/json/clean_logs.py +0 -0
  100. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/commands/json/clean_preference.py +0 -0
  101. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/commands/json/const.py +0 -0
  102. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/commands/json/continuous_cleaning.py +0 -0
  103. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/commands/json/custom.py +0 -0
  104. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/commands/json/multimap_state.py +0 -0
  105. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/commands/json/play_sound.py +0 -0
  106. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/commands/json/relocation.py +0 -0
  107. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/commands/json/true_detect.py +0 -0
  108. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/commands/xml/common.py +0 -0
  109. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/const.py +0 -0
  110. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/events/base.py +0 -0
  111. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/events/fan_speed.py +0 -0
  112. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/events/network.py +0 -0
  113. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/events/work_mode.py +0 -0
  114. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/exceptions.py +0 -0
  115. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/hardware/__init__.py +0 -0
  116. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/hardware/deebot/__init__.py +0 -0
  117. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/message.py +0 -0
  118. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/messages/__init__.py +0 -0
  119. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/messages/json/__init__.py +0 -0
  120. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/messages/json/battery.py +0 -0
  121. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/messages/json/stats.py +0 -0
  122. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client/py.typed +0 -0
  123. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client.egg-info/dependency_links.txt +0 -0
  124. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client.egg-info/requires.txt +0 -0
  125. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/deebot_client.egg-info/top_level.txt +0 -0
  126. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/mypy.ini +0 -0
  127. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/pytest.ini +0 -0
  128. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/requirements-dev.txt +0 -0
  129. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/requirements.txt +0 -0
  130. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/scripts/check_getLogger.sh +0 -0
  131. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/scripts/run-in-env.sh +0 -0
  132. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/setup.cfg +0 -0
  133. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/tests/__init__.py +0 -0
  134. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/tests/commands/__init__.py +0 -0
  135. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/tests/commands/json/test_battery.py +0 -0
  136. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/tests/commands/json/test_charge_state.py +0 -0
  137. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/tests/commands/json/test_clean_count.py +0 -0
  138. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/tests/commands/json/test_fan_speed.py +0 -0
  139. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/tests/commands/json/test_network.py +0 -0
  140. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/tests/commands/json/test_volume.py +0 -0
  141. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/tests/commands/json/test_work_mode.py +0 -0
  142. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/tests/events/__init__.py +0 -0
  143. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/tests/events/test_water_info.py +0 -0
  144. {deebot-client-3.0.3.dev0/tests/hardware → deebot-client-4.0.0/tests/fixtures}/__init__.py +0 -0
  145. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/tests/fixtures/mqtt_server.py +0 -0
  146. {deebot-client-3.0.3.dev0/tests/messages/json → deebot-client-4.0.0/tests/hardware}/__init__.py +0 -0
  147. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/tests/helpers/__init__.py +0 -0
  148. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/tests/helpers/tasks.py +0 -0
  149. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/tests/messages/__init__.py +0 -0
  150. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/tests/messages/json/test_battery.py +0 -0
  151. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/tests/messages/json/test_stats.py +0 -0
  152. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/tests/messages/test_get_messages.py +0 -0
  153. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/tests/test_map.py +0 -0
  154. {deebot-client-3.0.3.dev0 → deebot-client-4.0.0}/tests/test_util.py +0 -0
@@ -5,6 +5,7 @@
5
5
  // Configure properties specific to VS Code.
6
6
  "vscode": {
7
7
  "extensions": [
8
+ "charliermarsh.ruff",
8
9
  "eamodio.gitlens",
9
10
  "github.vscode-pull-request-github",
10
11
  "ms-python.python",
@@ -15,6 +16,9 @@
15
16
  ],
16
17
  // Set *default* container specific settings.json values on container create.
17
18
  "settings": {
19
+ "[python]": {
20
+ "editor.defaultFormatter": "charliermarsh.ruff"
21
+ },
18
22
  "editor.formatOnPaste": false,
19
23
  "editor.formatOnSave": true,
20
24
  "editor.formatOnType": true,
@@ -41,7 +41,7 @@ body:
41
41
  validations:
42
42
  required: true
43
43
  attributes:
44
- label: On which deebot vacuum you have the issue?
44
+ label: On which deebot device (vacuum) you have the issue?
45
45
  placeholder: Deebot Ozmo 950
46
46
  - type: input
47
47
  id: version
@@ -18,7 +18,7 @@ jobs:
18
18
  - uses: "actions/checkout@v4"
19
19
  - name: Set up Python ${{ env.DEFAULT_PYTHON }}
20
20
  id: python
21
- uses: actions/setup-python@v4.7.1
21
+ uses: actions/setup-python@v5.0.0
22
22
  with:
23
23
  python-version: ${{ env.DEFAULT_PYTHON }}
24
24
  cache: "pip"
@@ -42,7 +42,7 @@ jobs:
42
42
  - uses: "actions/checkout@v4"
43
43
  - name: Set up Python ${{ env.DEFAULT_PYTHON }}
44
44
  id: python
45
- uses: actions/setup-python@v4.7.1
45
+ uses: actions/setup-python@v5.0.0
46
46
  with:
47
47
  python-version: ${{ env.DEFAULT_PYTHON }}
48
48
  cache: "pip"
@@ -23,7 +23,7 @@ jobs:
23
23
  uses: actions/checkout@v4
24
24
 
25
25
  - name: Set up Python
26
- uses: actions/setup-python@v4.7.1
26
+ uses: actions/setup-python@v5.0.0
27
27
  with:
28
28
  python-version: "3.11"
29
29
 
@@ -1,4 +1,5 @@
1
1
  ci:
2
+ autofix_prs: false
2
3
  skip:
3
4
  # This steps run in the ci workflow. Keep in sync
4
5
  - mypy
@@ -10,23 +11,19 @@ default_language_version:
10
11
 
11
12
  repos:
12
13
  - repo: https://github.com/astral-sh/ruff-pre-commit
13
- rev: v0.1.1
14
+ rev: v0.1.6
14
15
  hooks:
15
16
  - id: ruff
16
17
  args:
17
18
  - --fix
19
+ # - --unsafe-fixes
20
+ - id: ruff-format
18
21
  - repo: https://github.com/asottile/pyupgrade
19
22
  rev: v3.15.0
20
23
  hooks:
21
24
  - id: pyupgrade
22
25
  args:
23
26
  - --py311-plus
24
- - repo: https://github.com/psf/black-pre-commit-mirror
25
- rev: 23.10.0
26
- hooks:
27
- - id: black
28
- args:
29
- - --quiet
30
27
  - repo: https://github.com/codespell-project/codespell
31
28
  rev: v2.2.6
32
29
  hooks:
@@ -48,16 +45,16 @@ repos:
48
45
  args: [--branch, main, --branch, dev]
49
46
  - id: requirements-txt-fixer
50
47
  - repo: https://github.com/pre-commit/mirrors-prettier
51
- rev: v3.0.3
48
+ rev: v3.1.0
52
49
  hooks:
53
50
  - id: prettier
54
51
  additional_dependencies:
55
- - prettier@3.0.3
56
- - prettier-plugin-sort-json@3.0.1
52
+ - prettier@3.1.0
53
+ - prettier-plugin-sort-json@3.1.0
57
54
  exclude_types:
58
55
  - python
59
56
  - repo: https://github.com/adrienverge/yamllint.git
60
- rev: v1.32.0
57
+ rev: v1.33.0
61
58
  hooks:
62
59
  - id: yamllint
63
60
  - repo: local
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: deebot-client
3
- Version: 3.0.3.dev0
3
+ Version: 4.0.0
4
4
  Summary: Deebot client library in python 3
5
5
  Author-email: Robert Resch <robert@resch.dev>
6
6
  License: GPL-3.0
@@ -24,7 +24,7 @@ Requires-Dist: defusedxml
24
24
  Requires-Dist: numpy<2.0,>=1.23.2
25
25
  Requires-Dist: Pillow<11.0,>=10.0.1
26
26
 
27
- # Client Library for Deebot Vacuums
27
+ # Client Library for Deebot devices (Vacuums)
28
28
 
29
29
  [![PyPI - Downloads](https://img.shields.io/pypi/dw/deebot-client?style=for-the-badge)](https://pypi.org/project/deebot-client)
30
30
  <a href="https://www.buymeacoffee.com/edenhaus" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/default-black.png" width="150px" height="35px" alt="Buy Me A Coffee" style="height: 35px !important;width: 150px !important;" ></a>
@@ -57,7 +57,7 @@ from deebot_client.events import BatteryEvent
57
57
  from deebot_client.models import Configuration
58
58
  from deebot_client.mqtt_client import MqttClient, MqttConfiguration
59
59
  from deebot_client.util import md5
60
- from deebot_client.vacuum_bot import VacuumBot
60
+ from deebot_client.device import Device
61
61
 
62
62
  device_id = md5(str(time.time()))
63
63
  account_id = "your email or phonenumber (cn)"
@@ -78,7 +78,7 @@ async def main():
78
78
 
79
79
  devices_ = await api_client.get_devices()
80
80
 
81
- bot = VacuumBot(devices_[0], authenticator)
81
+ bot = Device(devices_[0], authenticator)
82
82
 
83
83
  mqtt_config = MqttConfiguration(config=config)
84
84
  mqtt = MqttClient(mqtt_config, authenticator)
@@ -1,4 +1,4 @@
1
- # Client Library for Deebot Vacuums
1
+ # Client Library for Deebot devices (Vacuums)
2
2
 
3
3
  [![PyPI - Downloads](https://img.shields.io/pypi/dw/deebot-client?style=for-the-badge)](https://pypi.org/project/deebot-client)
4
4
  <a href="https://www.buymeacoffee.com/edenhaus" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/default-black.png" width="150px" height="35px" alt="Buy Me A Coffee" style="height: 35px !important;width: 150px !important;" ></a>
@@ -31,7 +31,7 @@ from deebot_client.events import BatteryEvent
31
31
  from deebot_client.models import Configuration
32
32
  from deebot_client.mqtt_client import MqttClient, MqttConfiguration
33
33
  from deebot_client.util import md5
34
- from deebot_client.vacuum_bot import VacuumBot
34
+ from deebot_client.device import Device
35
35
 
36
36
  device_id = md5(str(time.time()))
37
37
  account_id = "your email or phonenumber (cn)"
@@ -52,7 +52,7 @@ async def main():
52
52
 
53
53
  devices_ = await api_client.get_devices()
54
54
 
55
- bot = VacuumBot(devices_[0], authenticator)
55
+ bot = Device(devices_[0], authenticator)
56
56
 
57
57
  mqtt_config = MqttConfiguration(config=config)
58
58
  mqtt = MqttClient(mqtt_config, authenticator)
@@ -15,7 +15,7 @@ _LOGGER = get_logger(__name__)
15
15
  class ApiClient:
16
16
  """Api client."""
17
17
 
18
- def __init__(self, authenticator: Authenticator):
18
+ def __init__(self, authenticator: Authenticator) -> None:
19
19
  self._authenticator = authenticator
20
20
 
21
21
  async def get_devices(self) -> list[DeviceInfo]:
@@ -38,9 +38,8 @@ class ApiClient:
38
38
  _LOGGER.debug("Skipping device as it is not supported: %s", device)
39
39
  return devices
40
40
  _LOGGER.error("Failed to get devices: %s", resp)
41
- raise ApiError(
42
- f"failure {resp.get('error', '')} ({resp.get('errno', '')}) on getting devices"
43
- )
41
+ msg = f"failure {resp.get('error', '')} ({resp.get('errno', '')}) on getting devices"
42
+ raise ApiError(msg)
44
43
 
45
44
  async def get_product_iot_map(self) -> dict[str, Any]:
46
45
  """Get product iot map."""
@@ -55,6 +54,5 @@ class ApiClient:
55
54
  result[entry["classid"]] = entry["product"]
56
55
  return result
57
56
  _LOGGER.error("Failed to get product iot map")
58
- raise ApiError(
59
- f"failure {resp['error']} ({resp['errno']}) on getting product iot map"
60
- )
57
+ msg = f"failure {resp['error']} ({resp['errno']}) on getting product iot map"
58
+ raise ApiError(msg)
@@ -51,7 +51,7 @@ class _AuthClient:
51
51
  config: Configuration,
52
52
  account_id: str,
53
53
  password_hash: str,
54
- ):
54
+ ) -> None:
55
55
  self._config = config
56
56
  self._account_id = account_id
57
57
  self._password_hash = password_hash
@@ -107,7 +107,7 @@ class _AuthClient:
107
107
  content_type = res.headers.get(hdrs.CONTENT_TYPE, "").lower()
108
108
  json = await res.json(content_type=content_type)
109
109
  _LOGGER.debug("got %s", json)
110
- # todo better error handling # pylint: disable=fixme
110
+ # TODO better error handling # pylint: disable=fixme
111
111
  if json["code"] == "0000":
112
112
  data: dict[str, Any] = json["data"]
113
113
  return data
@@ -115,9 +115,8 @@ class _AuthClient:
115
115
  raise InvalidAuthenticationError
116
116
 
117
117
  _LOGGER.error("call to %s failed with %s", url, json)
118
- raise AuthenticationError(
119
- f"failure code {json['code']} ({json['msg']}) for call {url}"
120
- )
118
+ msg = f"failure code {json['code']} ({json['msg']}) for call {url}"
119
+ raise AuthenticationError(msg)
121
120
 
122
121
  async def __call_login_api(
123
122
  self, account_id: str, password_hash: str
@@ -204,9 +203,10 @@ class _AuthClient:
204
203
  continue
205
204
 
206
205
  _LOGGER.error("call to %s failed with %s", _PATH_USERS_USER, resp)
207
- raise AuthenticationError(
206
+ msg = (
208
207
  f"failure {resp['error']} ({resp['errno']}) for call {_PATH_USERS_USER}"
209
208
  )
209
+ raise AuthenticationError(msg)
210
210
 
211
211
  raise AuthenticationError("failed to login with token")
212
212
 
@@ -302,7 +302,7 @@ class Authenticator:
302
302
  config: Configuration,
303
303
  account_id: str,
304
304
  password_hash: str,
305
- ):
305
+ ) -> None:
306
306
  self._auth_client = _AuthClient(
307
307
  config,
308
308
  account_id,
@@ -317,7 +317,7 @@ class Authenticator:
317
317
  self._refresh_handle: asyncio.TimerHandle | None = None
318
318
  self._tasks: set[asyncio.Future[Any]] = set()
319
319
 
320
- async def authenticate(self, force: bool = False) -> Credentials:
320
+ async def authenticate(self, *, force: bool = False) -> Credentials:
321
321
  """Authenticate on ecovacs servers."""
322
322
  async with self._lock:
323
323
  if (
@@ -379,7 +379,7 @@ class Authenticator:
379
379
 
380
380
  async def async_refresh() -> None:
381
381
  try:
382
- await self.authenticate(True)
382
+ await self.authenticate(force=True)
383
383
  except Exception: # pylint: disable=broad-except
384
384
  _LOGGER.exception("An exception occurred during refreshing token")
385
385
 
@@ -4,8 +4,7 @@ from dataclasses import dataclass, field, fields, is_dataclass
4
4
  from types import MappingProxyType
5
5
  from typing import TYPE_CHECKING, Any, Generic, TypeVar
6
6
 
7
- from deebot_client.command import Command
8
- from deebot_client.commands.json.common import SetCommand
7
+ from deebot_client.command import Command, SetCommand
9
8
  from deebot_client.events import (
10
9
  AdvancedModeEvent,
11
10
  AvailabilityEvent,
@@ -35,12 +34,14 @@ from deebot_client.events import (
35
34
  StatsEvent,
36
35
  TotalStatsEvent,
37
36
  TrueDetectEvent,
37
+ VoiceAssistantStateEvent,
38
38
  VolumeEvent,
39
39
  WaterAmount,
40
40
  WaterInfoEvent,
41
41
  WorkMode,
42
42
  WorkModeEvent,
43
43
  )
44
+ from deebot_client.events.efficiency_mode import EfficiencyMode, EfficiencyModeEvent
44
45
  from deebot_client.models import CleanAction, CleanMode
45
46
 
46
47
  if TYPE_CHECKING:
@@ -121,7 +122,7 @@ class CapabilityClean:
121
122
  action: CapabilityCleanAction
122
123
  continuous: CapabilitySetEnable[ContinuousCleaningEvent]
123
124
  count: CapabilitySet[CleanCountEvent, int] | None = None
124
- log: CapabilityEvent[CleanLogEvent]
125
+ log: CapabilityEvent[CleanLogEvent] | None = None
125
126
  preference: CapabilitySetEnable[CleanPreferenceEvent] | None = None
126
127
  work_mode: CapabilitySetTypes[WorkModeEvent, WorkMode] | None = None
127
128
 
@@ -169,7 +170,11 @@ class CapabilitySettings:
169
170
 
170
171
  advanced_mode: CapabilitySetEnable[AdvancedModeEvent]
171
172
  carpet_auto_fan_boost: CapabilitySetEnable[CarpetAutoFanBoostEvent]
173
+ efficiency_mode: (
174
+ CapabilitySetTypes[EfficiencyModeEvent, EfficiencyMode] | None
175
+ ) = None
172
176
  true_detect: CapabilitySetEnable[TrueDetectEvent] | None = None
177
+ voice_assistant: CapabilitySetEnable[VoiceAssistantStateEvent] | None = None
173
178
  volume: CapabilitySet[VolumeEvent, int]
174
179
 
175
180
 
@@ -2,15 +2,17 @@
2
2
  from abc import ABC, abstractmethod
3
3
  import asyncio
4
4
  from dataclasses import dataclass, field
5
+ from types import MappingProxyType
5
6
  from typing import Any, final
6
7
 
8
+ from deebot_client.events import AvailabilityEvent
7
9
  from deebot_client.exceptions import DeebotError
8
10
 
9
11
  from .authentication import Authenticator
10
12
  from .const import PATH_API_IOT_DEVMANAGER, REQUEST_HEADERS, DataType
11
13
  from .event_bus import EventBus
12
14
  from .logging_filter import get_logger
13
- from .message import HandlingResult, HandlingState
15
+ from .message import HandlingResult, HandlingState, MessageBody
14
16
  from .models import DeviceInfo
15
17
 
16
18
  _LOGGER = get_logger(__name__)
@@ -53,7 +55,7 @@ class Command(ABC):
53
55
  @classmethod
54
56
  @abstractmethod
55
57
  def data_type(cls) -> DataType:
56
- """Data type.""" # noqa: D401
58
+ """Data type."""
57
59
 
58
60
  @abstractmethod
59
61
  def _get_payload(self) -> dict[str, Any] | list[Any] | str:
@@ -189,6 +191,49 @@ class Command(ABC):
189
191
  return hash(self.name) + hash(self._args)
190
192
 
191
193
 
194
+ class CommandWithMessageHandling(Command, MessageBody, ABC):
195
+ """Command, which handle response by itself."""
196
+
197
+ _is_available_check: bool = False
198
+
199
+ def _handle_response(
200
+ self, event_bus: EventBus, response: dict[str, Any]
201
+ ) -> CommandResult:
202
+ """Handle response from a command.
203
+
204
+ :return: A message response
205
+ """
206
+ if response.get("ret") == "ok":
207
+ data = response.get("resp", response)
208
+ result = self.handle(event_bus, data)
209
+ return CommandResult(result.state, result.args)
210
+
211
+ if errno := response.get("errno", None):
212
+ match errno:
213
+ case 4200:
214
+ # bot offline
215
+ _LOGGER.info(
216
+ 'Device is offline. Could not execute command "%s"', self.name
217
+ )
218
+ event_bus.notify(AvailabilityEvent(available=False))
219
+ return CommandResult(HandlingState.FAILED)
220
+ case 500:
221
+ if self._is_available_check:
222
+ _LOGGER.info(
223
+ 'No response received for command "%s" during availability-check.',
224
+ self.name,
225
+ )
226
+ else:
227
+ _LOGGER.warning(
228
+ 'No response received for command "%s". This can happen if the device has network issues or does not support the command',
229
+ self.name,
230
+ )
231
+ return CommandResult(HandlingState.FAILED)
232
+
233
+ _LOGGER.warning('Command "%s" was not successfully.', self.name)
234
+ return CommandResult(HandlingState.ANALYSE)
235
+
236
+
192
237
  @dataclass
193
238
  class InitParam:
194
239
  """Init param."""
@@ -200,7 +245,7 @@ class InitParam:
200
245
  class CommandMqttP2P(Command, ABC):
201
246
  """Command which can handle mqtt p2p messages."""
202
247
 
203
- _mqtt_params: dict[str, InitParam | None]
248
+ _mqtt_params: MappingProxyType[str, InitParam | None]
204
249
 
205
250
  @abstractmethod
206
251
  def handle_mqtt_p2p(self, event_bus: EventBus, response: dict[str, Any]) -> None:
@@ -230,10 +275,29 @@ def _pop_or_raise(name: str, type_: type, data: dict[str, Any]) -> Any:
230
275
  try:
231
276
  value = data.pop(name)
232
277
  except KeyError as err:
233
- raise DeebotError(f'"{name}" is missing in {data}') from err
278
+ msg = f'"{name}" is missing in {data}'
279
+ raise DeebotError(msg) from err
234
280
  try:
235
281
  return type_(value)
236
282
  except ValueError as err:
237
- raise DeebotError(
238
- f'Could not convert "{value}" of {name} into {type_}'
239
- ) from err
283
+ msg = f'Could not convert "{value}" of {name} into {type_}'
284
+ raise DeebotError(msg) from err
285
+
286
+
287
+ class SetCommand(CommandWithMessageHandling, CommandMqttP2P, ABC):
288
+ """Base set command.
289
+
290
+ Command needs to be linked to the "get" command, for handling (updating) the sensors.
291
+ """
292
+
293
+ @property
294
+ @abstractmethod
295
+ def get_command(self) -> type[CommandWithMessageHandling]:
296
+ """Return the corresponding "get" command."""
297
+ raise NotImplementedError # pragma: no cover
298
+
299
+ def handle_mqtt_p2p(self, event_bus: EventBus, response: dict[str, Any]) -> None:
300
+ """Handle response received over the mqtt channel "p2p"."""
301
+ result = self.handle(event_bus, response)
302
+ if result.state == HandlingState.SUCCESS and isinstance(self._args, dict):
303
+ self.get_command.handle(event_bus, self._args)
@@ -1,4 +1,4 @@
1
- """Commands module."""
1
+ """Json commands module."""
2
2
  from deebot_client.command import Command, CommandMqttP2P
3
3
 
4
4
  from .advanced_mode import GetAdvancedMode, SetAdvancedMode
@@ -12,6 +12,7 @@ from .clean_logs import GetCleanLogs
12
12
  from .clean_preference import GetCleanPreference, SetCleanPreference
13
13
  from .common import JsonCommand
14
14
  from .continuous_cleaning import GetContinuousCleaning, SetContinuousCleaning
15
+ from .efficiency import GetEfficiencyMode, SetEfficiencyMode
15
16
  from .error import GetError
16
17
  from .fan_speed import GetFanSpeed, SetFanSpeed
17
18
  from .life_span import GetLifeSpan, ResetLifeSpan
@@ -30,6 +31,7 @@ from .pos import GetPos
30
31
  from .relocation import SetRelocationState
31
32
  from .stats import GetStats, GetTotalStats
32
33
  from .true_detect import GetTrueDetect, SetTrueDetect
34
+ from .voice_assistant_state import GetVoiceAssistantState, SetVoiceAssistantState
33
35
  from .volume import GetVolume, SetVolume
34
36
  from .water_info import GetWaterInfo, SetWaterInfo
35
37
  from .work_mode import GetWorkMode, SetWorkMode
@@ -52,6 +54,8 @@ __all__ = [
52
54
  "GetCleanLogs",
53
55
  "GetContinuousCleaning",
54
56
  "SetContinuousCleaning",
57
+ "GetEfficiencyMode",
58
+ "SetEfficiencyMode",
55
59
  "GetError",
56
60
  "GetFanSpeed",
57
61
  "SetFanSpeed",
@@ -73,6 +77,8 @@ __all__ = [
73
77
  "GetTotalStats",
74
78
  "GetTrueDetect",
75
79
  "SetTrueDetect",
80
+ "GetVoiceAssistantState",
81
+ "SetVoiceAssistantState",
76
82
  "GetVolume",
77
83
  "SetVolume",
78
84
  "GetWaterInfo",
@@ -111,6 +117,9 @@ _COMMANDS: list[type[JsonCommand]] = [
111
117
  GetContinuousCleaning,
112
118
  SetContinuousCleaning,
113
119
 
120
+ GetEfficiencyMode,
121
+ SetEfficiencyMode,
122
+
114
123
  GetError,
115
124
 
116
125
  GetFanSpeed,
@@ -143,6 +152,9 @@ _COMMANDS: list[type[JsonCommand]] = [
143
152
  GetTrueDetect,
144
153
  SetTrueDetect,
145
154
 
155
+ GetVoiceAssistantState,
156
+ SetVoiceAssistantState,
157
+
146
158
  GetVolume,
147
159
  SetVolume,
148
160
 
@@ -155,7 +167,8 @@ _COMMANDS: list[type[JsonCommand]] = [
155
167
  # fmt: on
156
168
 
157
169
  COMMANDS: dict[str, type[Command]] = {
158
- cmd.name: cmd for cmd in _COMMANDS # type: ignore[misc]
170
+ cmd.name: cmd # type: ignore[misc]
171
+ for cmd in _COMMANDS
159
172
  }
160
173
 
161
174
  COMMANDS_WITH_MQTT_P2P_HANDLING: dict[str, type[CommandMqttP2P]] = {
@@ -1,14 +1,14 @@
1
1
  """Battery commands."""
2
2
  from deebot_client.messages.json import OnBattery
3
3
 
4
- from .common import CommandWithMessageHandling
4
+ from .common import JsonCommandWithMessageHandling
5
5
 
6
6
 
7
- class GetBattery(OnBattery, CommandWithMessageHandling):
7
+ class GetBattery(OnBattery, JsonCommandWithMessageHandling):
8
8
  """Get battery command."""
9
9
 
10
10
  name = "getBattery"
11
11
 
12
- def __init__(self, is_available_check: bool = False) -> None:
12
+ def __init__(self, *, is_available_check: bool = False) -> None:
13
13
  super().__init__()
14
14
  self._is_available_check = is_available_check
@@ -5,7 +5,7 @@ from deebot_client.event_bus import EventBus
5
5
  from deebot_client.events import StateEvent
6
6
  from deebot_client.logging_filter import get_logger
7
7
  from deebot_client.message import HandlingResult
8
- from deebot_client.models import VacuumState
8
+ from deebot_client.models import State
9
9
 
10
10
  from .common import ExecuteCommand
11
11
  from .const import CODE
@@ -29,12 +29,12 @@ class Charge(ExecuteCommand):
29
29
  """
30
30
  code = int(body.get(CODE, -1))
31
31
  if code == 0:
32
- event_bus.notify(StateEvent(VacuumState.RETURNING))
32
+ event_bus.notify(StateEvent(State.RETURNING))
33
33
  return HandlingResult.success()
34
34
 
35
35
  if code == 30007:
36
36
  # bot is already charging
37
- event_bus.notify(StateEvent(VacuumState.DOCKED))
37
+ event_bus.notify(StateEvent(State.DOCKED))
38
38
  return HandlingResult.success()
39
39
 
40
40
  return super()._handle_body(event_bus, body)
@@ -4,13 +4,13 @@ from typing import Any
4
4
  from deebot_client.event_bus import EventBus
5
5
  from deebot_client.events import StateEvent
6
6
  from deebot_client.message import HandlingResult, MessageBodyDataDict
7
- from deebot_client.models import VacuumState
7
+ from deebot_client.models import State
8
8
 
9
- from .common import CommandWithMessageHandling
9
+ from .common import JsonCommandWithMessageHandling
10
10
  from .const import CODE
11
11
 
12
12
 
13
- class GetChargeState(CommandWithMessageHandling, MessageBodyDataDict):
13
+ class GetChargeState(JsonCommandWithMessageHandling, MessageBodyDataDict):
14
14
  """Get charge state command."""
15
15
 
16
16
  name = "getChargeState"
@@ -24,7 +24,7 @@ class GetChargeState(CommandWithMessageHandling, MessageBodyDataDict):
24
24
  :return: A message response
25
25
  """
26
26
  if data.get("isCharging") == 1:
27
- event_bus.notify(StateEvent(VacuumState.DOCKED))
27
+ event_bus.notify(StateEvent(State.DOCKED))
28
28
  return HandlingResult.success()
29
29
 
30
30
  @classmethod
@@ -33,17 +33,17 @@ class GetChargeState(CommandWithMessageHandling, MessageBodyDataDict):
33
33
  # Call this also if code is not in the body
34
34
  return super()._handle_body(event_bus, body)
35
35
 
36
- status: VacuumState | None = None
36
+ status: State | None = None
37
37
  if body.get("msg", None) == "fail":
38
38
  if body["code"] == "30007": # Already charging
39
- status = VacuumState.DOCKED
39
+ status = State.DOCKED
40
40
  elif body["code"] in ("3", "5"):
41
41
  # 3 -> Bot in stuck state, example dust bin out
42
42
  # 5 -> Busy with another command
43
- status = VacuumState.ERROR
43
+ status = State.ERROR
44
44
 
45
45
  if status:
46
- event_bus.notify(StateEvent(VacuumState.DOCKED))
46
+ event_bus.notify(StateEvent(State.DOCKED))
47
47
  return HandlingResult.success()
48
48
 
49
49
  return HandlingResult.analyse()
@@ -7,9 +7,9 @@ from deebot_client.event_bus import EventBus
7
7
  from deebot_client.events import StateEvent
8
8
  from deebot_client.logging_filter import get_logger
9
9
  from deebot_client.message import HandlingResult, MessageBodyDataDict
10
- from deebot_client.models import CleanAction, CleanMode, DeviceInfo, VacuumState
10
+ from deebot_client.models import CleanAction, CleanMode, DeviceInfo, State
11
11
 
12
- from .common import CommandWithMessageHandling, ExecuteCommand
12
+ from .common import ExecuteCommand, JsonCommandWithMessageHandling
13
13
 
14
14
  _LOGGER = get_logger(__name__)
15
15
 
@@ -30,12 +30,12 @@ class Clean(ExecuteCommand):
30
30
  if state and isinstance(self._args, dict):
31
31
  if (
32
32
  self._args["act"] == CleanAction.RESUME.value
33
- and state.state != VacuumState.PAUSED
33
+ and state.state != State.PAUSED
34
34
  ):
35
35
  self._args = self.__get_args(CleanAction.START)
36
36
  elif (
37
37
  self._args["act"] == CleanAction.START.value
38
- and state.state == VacuumState.PAUSED
38
+ and state.state == State.PAUSED
39
39
  ):
40
40
  self._args = self.__get_args(CleanAction.RESUME)
41
41
 
@@ -62,7 +62,7 @@ class CleanArea(Clean):
62
62
  self._args["count"] = cleanings
63
63
 
64
64
 
65
- class GetCleanInfo(CommandWithMessageHandling, MessageBodyDataDict):
65
+ class GetCleanInfo(JsonCommandWithMessageHandling, MessageBodyDataDict):
66
66
  """Get clean info command."""
67
67
 
68
68
  name = "getCleanInfo"
@@ -75,20 +75,19 @@ class GetCleanInfo(CommandWithMessageHandling, MessageBodyDataDict):
75
75
 
76
76
  :return: A message response
77
77
  """
78
-
79
- status: VacuumState | None = None
78
+ status: State | None = None
80
79
  state = data.get("state")
81
80
  if data.get("trigger") == "alert":
82
- status = VacuumState.ERROR
81
+ status = State.ERROR
83
82
  elif state == "clean":
84
83
  clean_state = data.get("cleanState", {})
85
84
  motion_state = clean_state.get("motionState")
86
85
  if motion_state == "working":
87
- status = VacuumState.CLEANING
86
+ status = State.CLEANING
88
87
  elif motion_state == "pause":
89
- status = VacuumState.PAUSED
88
+ status = State.PAUSED
90
89
  elif motion_state == "goCharging":
91
- status = VacuumState.RETURNING
90
+ status = State.RETURNING
92
91
 
93
92
  clean_type = clean_state.get("type")
94
93
  content = clean_state.get("content", {})
@@ -103,9 +102,9 @@ class GetCleanInfo(CommandWithMessageHandling, MessageBodyDataDict):
103
102
  _LOGGER.debug("Last custom area values (x1,y1,x2,y2): %s", area_values)
104
103
 
105
104
  elif state == "goCharging":
106
- status = VacuumState.RETURNING
105
+ status = State.RETURNING
107
106
  elif state == "idle":
108
- status = VacuumState.IDLE
107
+ status = State.IDLE
109
108
 
110
109
  if status:
111
110
  event_bus.notify(StateEvent(status))