pymammotion 0.4.16__tar.gz → 0.4.18__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 (124) hide show
  1. {pymammotion-0.4.16 → pymammotion-0.4.18}/PKG-INFO +1 -1
  2. pymammotion-0.4.18/pymammotion/aliyun/client.py +230 -0
  3. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/aliyun/cloud_gateway.py +26 -20
  4. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/http/http.py +9 -2
  5. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/mammotion/devices/base.py +2 -4
  6. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/mammotion/devices/mammotion.py +21 -11
  7. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/mammotion/devices/mammotion_bluetooth.py +0 -1
  8. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/mammotion/devices/mammotion_cloud.py +4 -4
  9. {pymammotion-0.4.16 → pymammotion-0.4.18}/pyproject.toml +1 -1
  10. {pymammotion-0.4.16 → pymammotion-0.4.18}/LICENSE +0 -0
  11. {pymammotion-0.4.16 → pymammotion-0.4.18}/README.md +0 -0
  12. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/__init__.py +0 -0
  13. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/aliyun/__init__.py +0 -0
  14. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/aliyun/model/aep_response.py +0 -0
  15. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/aliyun/model/connect_response.py +0 -0
  16. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/aliyun/model/dev_by_account_response.py +0 -0
  17. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/aliyun/model/login_by_oauth_response.py +0 -0
  18. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/aliyun/model/regions_response.py +0 -0
  19. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/aliyun/model/session_by_authcode_response.py +0 -0
  20. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/aliyun/model/stream_subscription_response.py +0 -0
  21. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/aliyun/tmp_constant.py +0 -0
  22. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/bluetooth/__init__.py +0 -0
  23. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/bluetooth/ble.py +0 -0
  24. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/bluetooth/ble_message.py +0 -0
  25. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/bluetooth/const.py +0 -0
  26. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/bluetooth/data/__init__.py +0 -0
  27. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/bluetooth/data/convert.py +0 -0
  28. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/bluetooth/data/framectrldata.py +0 -0
  29. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/bluetooth/data/notifydata.py +0 -0
  30. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/bluetooth/model/__init__.py +0 -0
  31. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/bluetooth/model/atomic_integer.py +0 -0
  32. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/const.py +0 -0
  33. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/data/__init__.py +0 -0
  34. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/data/model/__init__.py +0 -0
  35. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/data/model/account.py +0 -0
  36. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/data/model/device.py +0 -0
  37. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/data/model/device_config.py +0 -0
  38. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/data/model/device_info.py +0 -0
  39. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/data/model/device_limits.py +0 -0
  40. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/data/model/enums.py +0 -0
  41. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/data/model/excute_boarder_params.py +0 -0
  42. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/data/model/execute_boarder.py +0 -0
  43. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/data/model/generate_route_information.py +0 -0
  44. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/data/model/hash_list.py +0 -0
  45. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/data/model/location.py +0 -0
  46. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/data/model/mowing_modes.py +0 -0
  47. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/data/model/plan.py +0 -0
  48. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/data/model/rapid_state.py +0 -0
  49. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/data/model/raw_data.py +0 -0
  50. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/data/model/region_data.py +0 -0
  51. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/data/model/report_info.py +0 -0
  52. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/data/mqtt/__init__.py +0 -0
  53. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/data/mqtt/event.py +0 -0
  54. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/data/mqtt/properties.py +0 -0
  55. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/data/mqtt/status.py +0 -0
  56. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/data/state_manager.py +0 -0
  57. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/event/__init__.py +0 -0
  58. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/event/event.py +0 -0
  59. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/http/_init_.py +0 -0
  60. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/http/encryption.py +0 -0
  61. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/http/model/http.py +0 -0
  62. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/mammotion/__init__.py +0 -0
  63. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/mammotion/commands/__init__.py +0 -0
  64. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/mammotion/commands/abstract_message.py +0 -0
  65. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/mammotion/commands/mammotion_command.py +0 -0
  66. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/mammotion/commands/messages/__init__.py +0 -0
  67. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/mammotion/commands/messages/driver.py +0 -0
  68. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/mammotion/commands/messages/media.py +0 -0
  69. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/mammotion/commands/messages/navigation.py +0 -0
  70. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/mammotion/commands/messages/network.py +0 -0
  71. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/mammotion/commands/messages/ota.py +0 -0
  72. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/mammotion/commands/messages/system.py +0 -0
  73. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/mammotion/commands/messages/video.py +0 -0
  74. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/mammotion/control/__init__.py +0 -0
  75. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/mammotion/control/joystick.py +0 -0
  76. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/mammotion/devices/__init__.py +0 -0
  77. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/mqtt/__init__.py +0 -0
  78. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/mqtt/linkkit/__init__.py +0 -0
  79. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/mqtt/linkkit/h2client.py +0 -0
  80. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/mqtt/linkkit/linkkit.py +0 -0
  81. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/mqtt/mammotion_future.py +0 -0
  82. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/mqtt/mammotion_mqtt.py +0 -0
  83. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/proto/__init__.py +0 -0
  84. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/proto/basestation.proto +0 -0
  85. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/proto/basestation_pb2.py +0 -0
  86. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/proto/basestation_pb2.pyi +0 -0
  87. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/proto/common.proto +0 -0
  88. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/proto/common_pb2.py +0 -0
  89. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/proto/common_pb2.pyi +0 -0
  90. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/proto/dev_net.proto +0 -0
  91. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/proto/dev_net_pb2.py +0 -0
  92. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/proto/dev_net_pb2.pyi +0 -0
  93. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/proto/luba_msg.proto +0 -0
  94. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/proto/luba_msg_pb2.py +0 -0
  95. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/proto/luba_msg_pb2.pyi +0 -0
  96. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/proto/luba_mul.proto +0 -0
  97. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/proto/luba_mul_pb2.py +0 -0
  98. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/proto/luba_mul_pb2.pyi +0 -0
  99. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/proto/mctrl_driver.proto +0 -0
  100. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/proto/mctrl_driver_pb2.py +0 -0
  101. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/proto/mctrl_driver_pb2.pyi +0 -0
  102. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/proto/mctrl_nav.proto +0 -0
  103. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/proto/mctrl_nav_pb2.py +0 -0
  104. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/proto/mctrl_nav_pb2.pyi +0 -0
  105. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/proto/mctrl_ota.proto +0 -0
  106. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/proto/mctrl_ota_pb2.py +0 -0
  107. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/proto/mctrl_ota_pb2.pyi +0 -0
  108. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/proto/mctrl_pept.proto +0 -0
  109. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/proto/mctrl_pept_pb2.py +0 -0
  110. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/proto/mctrl_pept_pb2.pyi +0 -0
  111. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/proto/mctrl_sys.proto +0 -0
  112. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/proto/mctrl_sys_pb2.py +0 -0
  113. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/proto/mctrl_sys_pb2.pyi +0 -0
  114. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/py.typed +0 -0
  115. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/utility/constant/__init__.py +0 -0
  116. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/utility/constant/device_constant.py +0 -0
  117. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/utility/conversions.py +0 -0
  118. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/utility/datatype_converter.py +0 -0
  119. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/utility/device_config.py +0 -0
  120. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/utility/device_type.py +0 -0
  121. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/utility/map.py +0 -0
  122. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/utility/movement.py +0 -0
  123. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/utility/periodic.py +0 -0
  124. {pymammotion-0.4.16 → pymammotion-0.4.18}/pymammotion/utility/rocker_util.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: pymammotion
3
- Version: 0.4.16
3
+ Version: 0.4.18
4
4
  Summary:
5
5
  License: GPL-3.0
6
6
  Author: Michael Arthur
@@ -0,0 +1,230 @@
1
+ import time
2
+
3
+ from Tea.core import TeaCore
4
+ from Tea.exceptions import UnretryableException
5
+ from Tea.request import TeaRequest
6
+
7
+ try:
8
+ from typing import Dict
9
+ except ImportError:
10
+ pass
11
+
12
+ from alibabacloud_apigateway_util.client import Client as APIGatewayUtilClient
13
+ from alibabacloud_tea_util.client import Client as UtilClient
14
+
15
+
16
+ class Client:
17
+ """test"""
18
+
19
+ _app_key = None # type: str
20
+ _app_secret = None # type: str
21
+ _protocol = None # type: str
22
+ _user_agent = None # type: str
23
+ _read_timeout = None # type: int
24
+ _connect_timeout = None # type: int
25
+ _http_proxy = None # type: str
26
+ _https_proxy = None # type: str
27
+ _no_proxy = None # type: str
28
+ _max_idle_conns = None # type: int
29
+ _domain = None # type: str
30
+
31
+ def __init__(self, config) -> None:
32
+ self._domain = config.domain
33
+ self._app_key = config.app_key
34
+ self._app_secret = config.app_secret
35
+ self._protocol = config.protocol
36
+ self._read_timeout = config.read_timeout
37
+ self._connect_timeout = config.connect_timeout
38
+ self._http_proxy = config.http_proxy
39
+ self._https_proxy = config.https_proxy
40
+ self._no_proxy = config.no_proxy
41
+ self._max_idle_conns = config.max_idle_conns
42
+
43
+ def do_request(self, pathname, protocol, method, header, body, runtime):
44
+ """Send request
45
+
46
+ @type pathname: str
47
+ @param pathname: the url path
48
+
49
+ @type protocol: str
50
+ @param protocol: http or https
51
+
52
+ @type method: str
53
+ @param method: example GET
54
+
55
+ @type header: Dict[str, str]
56
+ @param header: request header
57
+
58
+ @type body: iot_api_gateway_models.IoTApiRequest
59
+ @param body: the object of IoTApiRequest
60
+
61
+ @type runtime: util_models.RuntimeOptions
62
+ @param runtime: which controls some details of call api, such as retry times
63
+
64
+ @rtype: TeaResponse
65
+ @return: the response
66
+ """
67
+ body.validate()
68
+ runtime.validate()
69
+ _runtime = {
70
+ "timeouted": "retry",
71
+ "readTimeout": UtilClient.default_number(runtime.read_timeout, self._read_timeout),
72
+ "connectTimeout": UtilClient.default_number(runtime.connect_timeout, self._connect_timeout),
73
+ "httpProxy": UtilClient.default_string(runtime.http_proxy, self._http_proxy),
74
+ "httpsProxy": UtilClient.default_string(runtime.https_proxy, self._https_proxy),
75
+ "noProxy": UtilClient.default_string(runtime.no_proxy, self._no_proxy),
76
+ "maxIdleConns": UtilClient.default_number(runtime.max_idle_conns, self._max_idle_conns),
77
+ "retry": {
78
+ "retryable": runtime.autoretry,
79
+ "maxAttempts": UtilClient.default_number(runtime.max_attempts, 3),
80
+ },
81
+ "backoff": {
82
+ "policy": UtilClient.default_string(runtime.backoff_policy, "no"),
83
+ "period": UtilClient.default_number(runtime.backoff_period, 1),
84
+ },
85
+ "ignoreSSL": runtime.ignore_ssl,
86
+ }
87
+ _last_request = None
88
+ _last_exception = None
89
+ _now = time.time()
90
+ _retry_times = 0
91
+ while TeaCore.allow_retry(_runtime.get("retry"), _retry_times, _now):
92
+ if _retry_times > 0:
93
+ _backoff_time = TeaCore.get_backoff_time(_runtime.get("backoff"), _retry_times)
94
+ if _backoff_time > 0:
95
+ TeaCore.sleep(_backoff_time)
96
+ _retry_times = _retry_times + 1
97
+ try:
98
+ _request = TeaRequest()
99
+ _request.protocol = UtilClient.default_string(self._protocol, protocol)
100
+ _request.method = UtilClient.default_string(method, "POST")
101
+ _request.pathname = pathname
102
+ _request.headers = TeaCore.merge(
103
+ {
104
+ "host": self._domain,
105
+ "date": UtilClient.get_date_utcstring(),
106
+ "x-ca-nonce": UtilClient.get_nonce(),
107
+ "x-ca-key": self._app_key,
108
+ "x-ca-signaturemethod": "HmacSHA256",
109
+ "accept": "application/json",
110
+ "user-agent": self.get_user_agent(),
111
+ },
112
+ header,
113
+ )
114
+ if UtilClient.empty(body.id):
115
+ body.id = UtilClient.get_nonce()
116
+ if not UtilClient.is_unset(body):
117
+ _request.headers["content-type"] = "application/octet-stream"
118
+ _request.headers["content-md5"] = APIGatewayUtilClient.get_content_md5(
119
+ UtilClient.to_jsonstring(TeaCore.to_map(body))
120
+ )
121
+ _request.body = UtilClient.to_jsonstring(TeaCore.to_map(body))
122
+ _request.headers["x-ca-signature"] = APIGatewayUtilClient.get_signature(_request, self._app_secret)
123
+ _last_request = _request
124
+ _response = TeaCore.do_action(_request, _runtime)
125
+ return _response
126
+ except Exception as e:
127
+ if TeaCore.is_retryable(e):
128
+ _last_exception = e
129
+ continue
130
+ raise e
131
+ raise UnretryableException(_last_request, _last_exception)
132
+
133
+ async def async_do_request(self, pathname, protocol, method, header, body, runtime):
134
+ """Send request
135
+
136
+ @type pathname: str
137
+ @param pathname: the url path
138
+
139
+ @type protocol: str
140
+ @param protocol: http or https
141
+
142
+ @type method: str
143
+ @param method: example GET
144
+
145
+ @type header: Dict[str, str]
146
+ @param header: request header
147
+
148
+ @type body: iot_api_gateway_models.IoTApiRequest
149
+ @param body: the object of IoTApiRequest
150
+
151
+ @type runtime: util_models.RuntimeOptions
152
+ @param runtime: which controls some details of call api, such as retry times
153
+
154
+ @rtype: TeaResponse
155
+ @return: the response
156
+ """
157
+ body.validate()
158
+ runtime.validate()
159
+ _runtime = {
160
+ "timeouted": "retry",
161
+ "readTimeout": UtilClient.default_number(runtime.read_timeout, self._read_timeout),
162
+ "connectTimeout": UtilClient.default_number(runtime.connect_timeout, self._connect_timeout),
163
+ "httpProxy": UtilClient.default_string(runtime.http_proxy, self._http_proxy),
164
+ "httpsProxy": UtilClient.default_string(runtime.https_proxy, self._https_proxy),
165
+ "noProxy": UtilClient.default_string(runtime.no_proxy, self._no_proxy),
166
+ "maxIdleConns": UtilClient.default_number(runtime.max_idle_conns, self._max_idle_conns),
167
+ "retry": {
168
+ "retryable": runtime.autoretry,
169
+ "maxAttempts": UtilClient.default_number(runtime.max_attempts, 3),
170
+ },
171
+ "backoff": {
172
+ "policy": UtilClient.default_string(runtime.backoff_policy, "no"),
173
+ "period": UtilClient.default_number(runtime.backoff_period, 1),
174
+ },
175
+ "ignoreSSL": runtime.ignore_ssl,
176
+ }
177
+ _last_request = None
178
+ _last_exception = None
179
+ _now = time.time()
180
+ _retry_times = 0
181
+ while TeaCore.allow_retry(_runtime.get("retry"), _retry_times, _now):
182
+ if _retry_times > 0:
183
+ _backoff_time = TeaCore.get_backoff_time(_runtime.get("backoff"), _retry_times)
184
+ if _backoff_time > 0:
185
+ TeaCore.sleep(_backoff_time)
186
+ _retry_times = _retry_times + 1
187
+ try:
188
+ _request = TeaRequest()
189
+ _request.protocol = UtilClient.default_string(self._protocol, protocol)
190
+ _request.method = UtilClient.default_string(method, "POST")
191
+ _request.pathname = pathname
192
+ _request.headers = TeaCore.merge(
193
+ {
194
+ "host": self._domain,
195
+ "date": UtilClient.get_date_utcstring(),
196
+ "x-ca-nonce": UtilClient.get_nonce(),
197
+ "x-ca-key": self._app_key,
198
+ "x-ca-signaturemethod": "HmacSHA256",
199
+ "accept": "application/json",
200
+ "user-agent": self.get_user_agent(),
201
+ },
202
+ header,
203
+ )
204
+ if UtilClient.empty(body.id):
205
+ body.id = UtilClient.get_nonce()
206
+ if not UtilClient.is_unset(body):
207
+ _request.headers["content-type"] = "application/octet-stream"
208
+ _request.headers["content-md5"] = APIGatewayUtilClient.get_content_md5(
209
+ UtilClient.to_jsonstring(TeaCore.to_map(body))
210
+ )
211
+ _request.body = UtilClient.to_jsonstring(TeaCore.to_map(body))
212
+ _request.headers["x-ca-signature"] = APIGatewayUtilClient.get_signature(_request, self._app_secret)
213
+ _last_request = _request
214
+ _response = await TeaCore.async_do_action(_request, _runtime)
215
+ return _response
216
+ except Exception as e:
217
+ if TeaCore.is_retryable(e):
218
+ _last_exception = e
219
+ continue
220
+ raise e
221
+ raise UnretryableException(_last_request, _last_exception)
222
+
223
+ def get_user_agent(self):
224
+ """Get user agent
225
+
226
+ @rtype: str
227
+ @return: user agent
228
+ """
229
+ user_agent = UtilClient.get_user_agent(self._user_agent)
230
+ return user_agent
@@ -12,12 +12,12 @@ import time
12
12
  import uuid
13
13
 
14
14
  from aiohttp import ClientSession
15
- from alibabacloud_iot_api_gateway.client import Client
16
15
  from alibabacloud_iot_api_gateway.models import CommonParams, Config, IoTApiRequest
17
16
  from alibabacloud_tea_util.client import Client as UtilClient
18
17
  from alibabacloud_tea_util.models import RuntimeOptions
19
18
  from Tea.exceptions import UnretryableException
20
19
 
20
+ from pymammotion.aliyun.client import Client
21
21
  from pymammotion.aliyun.model.aep_response import AepResponse
22
22
  from pymammotion.aliyun.model.connect_response import ConnectResponse
23
23
  from pymammotion.aliyun.model.dev_by_account_response import ListingDevByAccountResponse
@@ -102,6 +102,7 @@ class CloudIOTGateway:
102
102
  dev_by_account: ListingDevByAccountResponse | None = None,
103
103
  ) -> None:
104
104
  """Initialize the CloudIOTGateway."""
105
+ self._iot_token_issued_at = None
105
106
  self.mammotion_http: MammotionHTTP | None = None
106
107
  self._app_key = APP_KEY
107
108
  self._app_secret = APP_SECRET
@@ -144,7 +145,7 @@ class CloudIOTGateway:
144
145
  hashlib.sha1,
145
146
  ).hexdigest()
146
147
 
147
- def get_region(self, country_code: str, auth_code: str):
148
+ async def get_region(self, country_code: str, auth_code: str):
148
149
  """Get the region based on country code and auth code."""
149
150
 
150
151
  if self._region_response is not None:
@@ -171,7 +172,9 @@ class CloudIOTGateway:
171
172
  )
172
173
 
173
174
  # send request
174
- response = client.do_request("/living/account/region/get", "https", "POST", None, body, RuntimeOptions())
175
+ response = await client.async_do_request(
176
+ "/living/account/region/get", "https", "POST", None, body, RuntimeOptions()
177
+ )
175
178
  logger.debug(response.status_message)
176
179
  logger.debug(response.headers)
177
180
  logger.debug(response.status_code)
@@ -191,7 +194,7 @@ class CloudIOTGateway:
191
194
 
192
195
  return response.body
193
196
 
194
- def aep_handle(self):
197
+ async def aep_handle(self):
195
198
  """Handle AEP authentication."""
196
199
  aep_domain = self.domain
197
200
 
@@ -230,7 +233,7 @@ class CloudIOTGateway:
230
233
  )
231
234
 
232
235
  # send request
233
- response = client.do_request("/app/aepauth/handle", "https", "POST", None, body, RuntimeOptions())
236
+ response = await client.async_do_request("/app/aepauth/handle", "https", "POST", None, body, RuntimeOptions())
234
237
  logger.debug(response.status_message)
235
238
  logger.debug(response.headers)
236
239
  logger.debug(response.status_code)
@@ -395,7 +398,7 @@ class CloudIOTGateway:
395
398
  return self._login_by_oauth_response
396
399
  raise LoginException(data)
397
400
 
398
- def session_by_auth_code(self):
401
+ async def session_by_auth_code(self):
399
402
  """Create a session by auth code."""
400
403
  config = Config(
401
404
  app_key=self._app_key,
@@ -420,7 +423,7 @@ class CloudIOTGateway:
420
423
  )
421
424
 
422
425
  # send request
423
- response = client.do_request(
426
+ response = await client.async_do_request(
424
427
  "/account/createSessionByAuthCode",
425
428
  "https",
426
429
  "POST",
@@ -452,7 +455,7 @@ class CloudIOTGateway:
452
455
 
453
456
  return response.body
454
457
 
455
- def sign_out(self) -> None:
458
+ async def sign_out(self) -> None:
456
459
  config = Config(
457
460
  app_key=self._app_key,
458
461
  app_secret=self._app_secret,
@@ -476,7 +479,7 @@ class CloudIOTGateway:
476
479
 
477
480
  # send request
478
481
  # possibly need to do this ourselves
479
- response = client.do_request(
482
+ response = await client.async_do_request(
480
483
  "/iotx/account/invalidSession",
481
484
  "https",
482
485
  "POST",
@@ -497,7 +500,7 @@ class CloudIOTGateway:
497
500
  logger.debug(response_body_dict)
498
501
  return response_body_dict
499
502
 
500
- def check_or_refresh_session(self):
503
+ async def check_or_refresh_session(self):
501
504
  """Check or refresh the session."""
502
505
  logger.debug("Trying to refresh token")
503
506
  config = Config(
@@ -523,7 +526,7 @@ class CloudIOTGateway:
523
526
 
524
527
  # send request
525
528
  # possibly need to do this ourselves
526
- response = client.do_request(
529
+ response = await client.async_do_request(
527
530
  "/account/checkOrRefreshSession",
528
531
  "https",
529
532
  "POST",
@@ -544,7 +547,7 @@ class CloudIOTGateway:
544
547
 
545
548
  if int(response_body_dict.get("code")) != 200:
546
549
  logger.error(response_body_dict)
547
- self.sign_out()
550
+ await self.sign_out()
548
551
  raise CheckSessionException("Error check or refresh token: " + response_body_dict.__str__())
549
552
 
550
553
  session = SessionByAuthCodeResponse.from_dict(response_body_dict)
@@ -562,7 +565,7 @@ class CloudIOTGateway:
562
565
  self._session_by_authcode_response = session
563
566
  self._iot_token_issued_at = int(time.time())
564
567
 
565
- def list_binding_by_account(self) -> ListingDevByAccountResponse:
568
+ async def list_binding_by_account(self) -> ListingDevByAccountResponse:
566
569
  """List bindings by account."""
567
570
  config = Config(
568
571
  app_key=self._app_key,
@@ -586,7 +589,9 @@ class CloudIOTGateway:
586
589
  )
587
590
 
588
591
  # send request
589
- response = client.do_request("/uc/listBindingByAccount", "https", "POST", None, body, RuntimeOptions())
592
+ response = await client.async_do_request(
593
+ "/uc/listBindingByAccount", "https", "POST", None, body, RuntimeOptions()
594
+ )
590
595
  logger.debug(response.status_message)
591
596
  logger.debug(response.headers)
592
597
  logger.debug(response.status_code)
@@ -604,7 +609,7 @@ class CloudIOTGateway:
604
609
  self._devices_by_account_response = ListingDevByAccountResponse.from_dict(response_body_dict)
605
610
  return self._devices_by_account_response
606
611
 
607
- def list_binding_by_dev(self, iot_id: str):
612
+ async def list_binding_by_dev(self, iot_id: str):
608
613
  config = Config(
609
614
  app_key=self._app_key,
610
615
  app_secret=self._app_secret,
@@ -627,7 +632,7 @@ class CloudIOTGateway:
627
632
  )
628
633
 
629
634
  # send request
630
- response = client.do_request("/uc/listBindingByDev", "https", "POST", None, body, RuntimeOptions())
635
+ response = await client.async_do_request("/uc/listBindingByDev", "https", "POST", None, body, RuntimeOptions())
631
636
  logger.debug(response.status_message)
632
637
  logger.debug(response.headers)
633
638
  logger.debug(response.status_code)
@@ -645,7 +650,7 @@ class CloudIOTGateway:
645
650
  self._devices_by_account_response = ListingDevByAccountResponse.from_dict(response_body_dict)
646
651
  return self._devices_by_account_response
647
652
 
648
- def send_cloud_command(self, iot_id: str, command: bytes) -> str:
653
+ async def send_cloud_command(self, iot_id: str, command: bytes) -> str:
649
654
  """Send a cloud command to the specified IoT device."""
650
655
 
651
656
  if command is None:
@@ -659,7 +664,7 @@ class CloudIOTGateway:
659
664
  if self._iot_token_issued_at + self._session_by_authcode_response.data.refreshTokenExpire > (
660
665
  int(time.time())
661
666
  ):
662
- self.check_or_refresh_session()
667
+ await self.check_or_refresh_session()
663
668
  else:
664
669
  raise AuthRefreshException("Refresh token expired. Please re-login")
665
670
 
@@ -694,7 +699,8 @@ class CloudIOTGateway:
694
699
  )
695
700
  logger.debug(self.converter.printBase64Binary(command))
696
701
  # send request
697
- response = client.do_request("/thing/service/invoke", "https", "POST", None, body, RuntimeOptions())
702
+ runtime_options = RuntimeOptions(autoretry=True, backoff_policy="yes")
703
+ response = await client.async_do_request("/thing/service/invoke", "https", "POST", None, body, runtime_options)
698
704
  logger.debug(response.status_message)
699
705
  logger.debug(response.headers)
700
706
  logger.debug(response.status_code)
@@ -716,7 +722,7 @@ class CloudIOTGateway:
716
722
 
717
723
  if response_body_dict.get("code") == 29003:
718
724
  logger.debug(self._session_by_authcode_response.data.identityId)
719
- self.sign_out()
725
+ await self.sign_out()
720
726
  raise SetupException(response_body_dict.get("code"), iot_id)
721
727
  if response_body_dict.get("code") == 6205:
722
728
  raise DeviceOfflineException(response_body_dict.get("code"), iot_id)
@@ -13,6 +13,8 @@ class MammotionHTTP:
13
13
  def __init__(self) -> None:
14
14
  self.code = None
15
15
  self.msg = None
16
+ self.account = None
17
+ self._password = None
16
18
  self.response: Response | None = None
17
19
  self.login_info: LoginResponseData | None = None
18
20
  self._headers = {"User-Agent": "okhttp/3.14.9", "App-Version": "google Pixel 2 XL taimen-Android 11,1.11.332"}
@@ -106,7 +108,12 @@ class MammotionHTTP:
106
108
  # Assuming the data format matches the expected structure
107
109
  return Response[StreamSubscriptionResponse].from_dict(data)
108
110
 
109
- async def login(self, username: str, password: str) -> Response[LoginResponseData]:
111
+ async def refresh_login(self) -> Response[LoginResponseData]:
112
+ return await self.login(self.account, self._password)
113
+
114
+ async def login(self, account: str, password: str) -> Response[LoginResponseData]:
115
+ self.account = account
116
+ self._password = password
110
117
  async with ClientSession(MAMMOTION_DOMAIN) as session:
111
118
  async with session.post(
112
119
  "/oauth/token",
@@ -118,7 +125,7 @@ class MammotionHTTP:
118
125
  "Ec-Version": "v1",
119
126
  },
120
127
  params=dict(
121
- username=self.encryption_utils.encryption_by_aes(username),
128
+ username=self.encryption_utils.encryption_by_aes(account),
122
129
  password=self.encryption_utils.encryption_by_aes(password),
123
130
  client_id=self.encryption_utils.encryption_by_aes(MAMMOTION_CLIENT_ID),
124
131
  client_secret=self.encryption_utils.encryption_by_aes(MAMMOTION_CLIENT_SECRET),
@@ -56,9 +56,7 @@ class MammotionBaseDevice:
56
56
  return
57
57
 
58
58
  for frame in missing_frames:
59
- await self.queue_command(
60
- "get_hash_response", sub_cmd=hash_ack.sub_cmd, total_frame=hash_ack.total_frame, current_frame=frame - 1
61
- )
59
+ await self.queue_command("get_hash_response", total_frame=hash_ack.total_frame, current_frame=frame - 1)
62
60
 
63
61
  async def commdata_response(self, common_data: NavGetCommDataAck | SvgMessageAckT) -> None:
64
62
  """Handle common data responses."""
@@ -231,7 +229,7 @@ class MammotionBaseDevice:
231
229
  # sub_cmd 4 is dump location (yuka)
232
230
  # jobs list
233
231
  #
234
- # hash_list_result = await self._send_command_with_args("get_all_boundary_hash_list", sub_cmd=3)
232
+ await self.queue_command("get_all_boundary_hash_list", sub_cmd=3)
235
233
 
236
234
  async def async_read_settings(self) -> None:
237
235
  """Read settings from device."""
@@ -187,6 +187,18 @@ class Mammotion:
187
187
  cloud_client = await self.login(account, password)
188
188
  await self.initiate_cloud_connection(account, cloud_client)
189
189
 
190
+ async def refresh_login(self, account: str) -> None:
191
+ async with self._login_lock:
192
+ exists: MammotionCloud | None = self.mqtt_list.get(account)
193
+ if not exists:
194
+ return
195
+ mammotion_http = exists.cloud_client.mammotion_http
196
+ await mammotion_http.refresh_login()
197
+ await self.connect_iot(mammotion_http, exists.cloud_client)
198
+ if not exists.is_connected():
199
+ loop = asyncio.get_running_loop()
200
+ await loop.run_in_executor(None, exists.connect_async)
201
+
190
202
  async def initiate_cloud_connection(self, account: str, cloud_client: CloudIOTGateway) -> None:
191
203
  loop = asyncio.get_running_loop()
192
204
  if mqtt := self.mqtt_list.get(account):
@@ -242,21 +254,19 @@ class Mammotion:
242
254
  cloud_client = CloudIOTGateway()
243
255
  mammotion_http = MammotionHTTP()
244
256
  await mammotion_http.login(account, password)
257
+ await cloud_client.list_binding_by_account()
258
+ await self.connect_iot(mammotion_http, cloud_client)
259
+ return cloud_client
260
+
261
+ @staticmethod
262
+ async def connect_iot(mammotion_http: MammotionHTTP, cloud_client: CloudIOTGateway) -> None:
245
263
  country_code = mammotion_http.login_info.userInformation.domainAbbreviation
246
- _LOGGER.debug("CountryCode: " + country_code)
247
- _LOGGER.debug("AuthCode: " + mammotion_http.login_info.authorization_code)
248
264
  cloud_client.set_http(mammotion_http)
249
- loop = asyncio.get_running_loop()
250
- await loop.run_in_executor(
251
- None, cloud_client.get_region, country_code, mammotion_http.login_info.authorization_code
252
- )
265
+ await cloud_client.get_region(country_code, mammotion_http.login_info.authorization_code)
253
266
  await cloud_client.connect()
254
267
  await cloud_client.login_by_oauth(country_code, mammotion_http.login_info.authorization_code)
255
- await loop.run_in_executor(None, cloud_client.aep_handle)
256
- await loop.run_in_executor(None, cloud_client.session_by_auth_code)
257
-
258
- await loop.run_in_executor(None, cloud_client.list_binding_by_account)
259
- return cloud_client
268
+ await cloud_client.aep_handle()
269
+ await cloud_client.session_by_auth_code()
260
270
 
261
271
  async def remove_device(self, name: str) -> None:
262
272
  await self.device_manager.remove_device(name)
@@ -106,7 +106,6 @@ class MammotionBaseBLEDevice(MammotionBaseDevice):
106
106
 
107
107
  async def _ble_sync(self) -> None:
108
108
  if self._client is not None and self._client.is_connected:
109
- _LOGGER.debug("BLE SYNC")
110
109
  command_bytes = self._commands.send_todev_ble_sync(2)
111
110
  await self._message.post_custom_data_bytes(command_bytes)
112
111
 
@@ -65,8 +65,8 @@ class MammotionCloud:
65
65
  def connect_async(self) -> None:
66
66
  self._mqtt_client.connect_async()
67
67
 
68
- def send_command(self, iot_id: str, command: bytes) -> None:
69
- self._mqtt_client.get_cloud_client().send_cloud_command(iot_id, command)
68
+ async def send_command(self, iot_id: str, command: bytes) -> None:
69
+ await self._mqtt_client.get_cloud_client().send_cloud_command(iot_id, command)
70
70
 
71
71
  async def on_connected(self) -> None:
72
72
  """Callback for when MQTT connects."""
@@ -102,7 +102,7 @@ class MammotionCloud:
102
102
  self._key = key
103
103
  _LOGGER.debug("Sending command: %s", key)
104
104
 
105
- await self.loop.run_in_executor(None, self._mqtt_client.get_cloud_client().send_cloud_command, iot_id, command)
105
+ await self._mqtt_client.get_cloud_client().send_cloud_command(iot_id, command)
106
106
  future = MammotionFuture(iot_id)
107
107
  self._waiting_queue.append(future)
108
108
  timeout = 5
@@ -244,7 +244,7 @@ class MammotionBaseCloudDevice(MammotionBaseDevice):
244
244
  command_bytes = self._commands.send_todev_ble_sync(3)
245
245
  loop = asyncio.get_running_loop()
246
246
  try:
247
- await loop.run_in_executor(None, self._mqtt.send_command, self.iot_id, command_bytes)
247
+ await self._mqtt.send_command(self.iot_id, command_bytes)
248
248
  except (CheckSessionException, SetupException):
249
249
  self._ble_sync_task.cancel()
250
250
 
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
4
4
 
5
5
  [project]
6
6
  name = "pymammotion"
7
- version = "0.4.16"
7
+ version = "0.4.18"
8
8
  license = "GPL-3.0"
9
9
  description = ""
10
10
  readme = "README.md"
File without changes
File without changes