pymammotion 0.2.62__py3-none-any.whl → 0.5.51__py3-none-any.whl

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.

Potentially problematic release.


This version of pymammotion might be problematic. Click here for more details.

Files changed (135) hide show
  1. pymammotion/__init__.py +9 -6
  2. pymammotion/aliyun/client.py +235 -0
  3. pymammotion/aliyun/cloud_gateway.py +320 -69
  4. pymammotion/aliyun/model/aep_response.py +1 -2
  5. pymammotion/aliyun/model/dev_by_account_response.py +170 -23
  6. pymammotion/aliyun/model/login_by_oauth_response.py +2 -3
  7. pymammotion/aliyun/model/regions_response.py +3 -3
  8. pymammotion/aliyun/model/session_by_authcode_response.py +2 -2
  9. pymammotion/aliyun/model/thing_response.py +12 -0
  10. pymammotion/aliyun/regions.py +62 -0
  11. pymammotion/aliyun/tea/core.py +297 -0
  12. pymammotion/bluetooth/ble.py +11 -15
  13. pymammotion/bluetooth/ble_message.py +389 -106
  14. pymammotion/bluetooth/model/atomic_integer.py +54 -0
  15. pymammotion/const.py +3 -0
  16. pymammotion/data/model/__init__.py +1 -2
  17. pymammotion/data/model/device.py +92 -240
  18. pymammotion/data/model/device_config.py +10 -24
  19. pymammotion/data/model/device_info.py +35 -0
  20. pymammotion/data/model/device_limits.py +49 -0
  21. pymammotion/data/model/enums.py +12 -2
  22. pymammotion/data/model/errors.py +12 -0
  23. pymammotion/data/model/events.py +14 -0
  24. pymammotion/data/model/generate_geojson.py +521 -0
  25. pymammotion/data/model/generate_route_information.py +3 -4
  26. pymammotion/data/model/hash_list.py +384 -48
  27. pymammotion/data/model/location.py +4 -4
  28. pymammotion/data/model/mowing_modes.py +24 -1
  29. pymammotion/data/model/raw_data.py +215 -0
  30. pymammotion/data/model/region_data.py +10 -11
  31. pymammotion/data/model/report_info.py +62 -6
  32. pymammotion/data/model/work.py +27 -0
  33. pymammotion/data/mower_state_manager.py +316 -0
  34. pymammotion/data/mqtt/event.py +73 -28
  35. pymammotion/data/mqtt/mammotion_properties.py +257 -0
  36. pymammotion/data/mqtt/properties.py +93 -78
  37. pymammotion/data/mqtt/status.py +18 -17
  38. pymammotion/event/event.py +32 -8
  39. pymammotion/homeassistant/__init__.py +3 -0
  40. pymammotion/homeassistant/mower_api.py +484 -0
  41. pymammotion/homeassistant/rtk_api.py +54 -0
  42. pymammotion/http/__init__.py +0 -0
  43. pymammotion/http/encryption.py +220 -0
  44. pymammotion/http/http.py +652 -44
  45. pymammotion/http/model/__init__.py +0 -0
  46. pymammotion/{aliyun/model/stream_subscription_response.py → http/model/camera_stream.py} +14 -2
  47. pymammotion/http/model/http.py +160 -9
  48. pymammotion/http/model/response_factory.py +61 -0
  49. pymammotion/http/model/rtk.py +16 -0
  50. pymammotion/mammotion/commands/abstract_message.py +7 -5
  51. pymammotion/mammotion/commands/mammotion_command.py +32 -3
  52. pymammotion/mammotion/commands/messages/basestation.py +43 -0
  53. pymammotion/mammotion/commands/messages/driver.py +61 -29
  54. pymammotion/mammotion/commands/messages/media.py +68 -15
  55. pymammotion/mammotion/commands/messages/navigation.py +61 -25
  56. pymammotion/mammotion/commands/messages/network.py +93 -100
  57. pymammotion/mammotion/commands/messages/ota.py +18 -18
  58. pymammotion/mammotion/commands/messages/system.py +97 -72
  59. pymammotion/mammotion/commands/messages/video.py +17 -12
  60. pymammotion/mammotion/devices/__init__.py +27 -3
  61. pymammotion/mammotion/devices/base.py +50 -127
  62. pymammotion/mammotion/devices/mammotion.py +447 -212
  63. pymammotion/mammotion/devices/mammotion_bluetooth.py +105 -60
  64. pymammotion/mammotion/devices/mammotion_cloud.py +157 -105
  65. pymammotion/mammotion/devices/mammotion_mower_ble.py +49 -0
  66. pymammotion/mammotion/devices/mammotion_mower_cloud.py +39 -0
  67. pymammotion/mammotion/devices/managers/managers.py +81 -0
  68. pymammotion/mammotion/devices/mower_device.py +124 -0
  69. pymammotion/mammotion/devices/mower_manager.py +107 -0
  70. pymammotion/mammotion/devices/rtk_ble.py +89 -0
  71. pymammotion/mammotion/devices/rtk_cloud.py +113 -0
  72. pymammotion/mammotion/devices/rtk_device.py +50 -0
  73. pymammotion/mammotion/devices/rtk_manager.py +122 -0
  74. pymammotion/mqtt/__init__.py +2 -1
  75. pymammotion/mqtt/aliyun_mqtt.py +232 -0
  76. pymammotion/mqtt/linkkit/__init__.py +5 -0
  77. pymammotion/mqtt/linkkit/h2client.py +585 -0
  78. pymammotion/mqtt/linkkit/linkkit.py +3023 -0
  79. pymammotion/mqtt/mammotion_mqtt.py +176 -169
  80. pymammotion/mqtt/mqtt_models.py +66 -0
  81. pymammotion/proto/__init__.py +4839 -4
  82. pymammotion/proto/basestation.proto +8 -0
  83. pymammotion/proto/basestation_pb2.py +11 -9
  84. pymammotion/proto/basestation_pb2.pyi +16 -2
  85. pymammotion/proto/dev_net.proto +79 -55
  86. pymammotion/proto/dev_net_pb2.py +60 -56
  87. pymammotion/proto/dev_net_pb2.pyi +49 -6
  88. pymammotion/proto/luba_msg.proto +2 -1
  89. pymammotion/proto/luba_msg_pb2.py +6 -6
  90. pymammotion/proto/luba_msg_pb2.pyi +1 -0
  91. pymammotion/proto/luba_mul.proto +62 -1
  92. pymammotion/proto/luba_mul_pb2.py +38 -22
  93. pymammotion/proto/luba_mul_pb2.pyi +94 -7
  94. pymammotion/proto/mctrl_driver.proto +44 -4
  95. pymammotion/proto/mctrl_driver_pb2.py +26 -14
  96. pymammotion/proto/mctrl_driver_pb2.pyi +66 -11
  97. pymammotion/proto/mctrl_nav.proto +97 -51
  98. pymammotion/proto/mctrl_nav_pb2.py +75 -67
  99. pymammotion/proto/mctrl_nav_pb2.pyi +142 -56
  100. pymammotion/proto/mctrl_ota.proto +40 -2
  101. pymammotion/proto/mctrl_ota_pb2.py +23 -13
  102. pymammotion/proto/mctrl_ota_pb2.pyi +67 -4
  103. pymammotion/proto/mctrl_pept.proto +8 -3
  104. pymammotion/proto/mctrl_pept_pb2.py +8 -6
  105. pymammotion/proto/mctrl_pept_pb2.pyi +14 -6
  106. pymammotion/proto/mctrl_sys.proto +325 -86
  107. pymammotion/proto/mctrl_sys_pb2.py +162 -98
  108. pymammotion/proto/mctrl_sys_pb2.pyi +451 -25
  109. pymammotion/proto/message_pool.py +3 -0
  110. pymammotion/proto/py.typed +0 -0
  111. pymammotion/utility/constant/device_constant.py +65 -21
  112. pymammotion/utility/datatype_converter.py +13 -12
  113. pymammotion/utility/device_config.py +755 -0
  114. pymammotion/utility/device_type.py +218 -21
  115. pymammotion/utility/map.py +238 -51
  116. pymammotion/utility/mur_mur_hash.py +159 -0
  117. {pymammotion-0.2.62.dist-info → pymammotion-0.5.51.dist-info}/METADATA +27 -31
  118. pymammotion-0.5.51.dist-info/RECORD +152 -0
  119. {pymammotion-0.2.62.dist-info → pymammotion-0.5.51.dist-info}/WHEEL +1 -1
  120. pymammotion/aliyun/cloud_service.py +0 -65
  121. pymammotion/data/model/plan.py +0 -58
  122. pymammotion/data/state_manager.py +0 -130
  123. pymammotion/proto/basestation.py +0 -59
  124. pymammotion/proto/common.py +0 -12
  125. pymammotion/proto/dev_net.py +0 -381
  126. pymammotion/proto/luba_msg.py +0 -81
  127. pymammotion/proto/luba_mul.py +0 -76
  128. pymammotion/proto/mctrl_driver.py +0 -100
  129. pymammotion/proto/mctrl_nav.py +0 -660
  130. pymammotion/proto/mctrl_ota.py +0 -48
  131. pymammotion/proto/mctrl_pept.py +0 -41
  132. pymammotion/proto/mctrl_sys.py +0 -574
  133. pymammotion-0.2.62.dist-info/RECORD +0 -125
  134. /pymammotion/{http/_init_.py → bluetooth/model/__init__.py} +0 -0
  135. {pymammotion-0.2.62.dist-info → pymammotion-0.5.51.dist-info/licenses}/LICENSE +0 -0
@@ -0,0 +1,220 @@
1
+ import base64
2
+ import logging
3
+ import secrets
4
+ import string
5
+
6
+ from cryptography.hazmat.backends import default_backend
7
+ from cryptography.hazmat.primitives import padding, serialization
8
+ from cryptography.hazmat.primitives.asymmetric import padding as rsa_padding
9
+ from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
10
+
11
+ _LOGGER = logging.getLogger(__name__)
12
+
13
+
14
+ class EncryptionUtils:
15
+ PRIVATE_KEY = """MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAOFizbd1fC5XNKJ89u0XNvPZNR/L
16
+ 0h547iSWjOCuvvMu76ZSaS3/Tu2C1C+XmlnmBWTyY4ON+xECiNUXm/aWQ3P0g+wf60zjPbNzgL2Q
17
+ 7njXJG6wka4KkbdQxUdS0TTpL256LnV1LsG855bsbJIJiQPbfUq6HbB5xH7sXdrmFu1DAgMBAAEC
18
+ gYEAoT2TGE1ncquWjyxBZup1uMvKkp25C23OSMSfslmxZ75LWjyY3HxK1eYDsKyPkwLZFxfFE6du
19
+ VwPuKiyCuk1ToPfnb4niTGzXPyC2PbO4SFrWL8n1YZ80M0bfTGI9dMCZvpmZJ41WYUsBaf2374lt
20
+ oEiDEHJp7MeXk/970xiKP1ECQQD65rLHk840q+FZS6kZVexJucPZj/YAII6klU1E20ctioe8Pi5m
21
+ WSPqclH27/t4FqdvP7tFqaavyXg+CEQpxmxLAkEA5fddDuzcjWgF9pl9fP7/baFMYjUS9z1Vc3gx
22
+ CnvAgCnv71wjDQhvsUc6sAiidsBGFDyud06RyyLcOlQchMb36QJBAIui/Xjpn+fciQxjeXcqRNk7
23
+ U+6vml+zvu+GUHyz9Uc5RBXWHYjEr6J5gXiHU1MgeIsH0zgQFT7cR9luTFFbp0UCQFIntfogCocG
24
+ E6NOoHMoUi5jQnuPRHBJXB69YJ/DKDlhQhN8EhWU3voxXTkITKop9J9EMnvy+MjecljwNaQFxQkC
25
+ QB9lz67iDe9Gj8NxSElVZxUm9EfbL1RPqTZPx/lADR06CPB8pP3Bl5/5/5RGzc+UTZ+wX5GWKvC7
26
+ zUJaROxQB+E=""".replace(" ", "")
27
+
28
+ PUBLIC_KEY_PROD = """MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApLbeSgOvnwLTWbhaBQWNnnHMtSDAi
29
+ Gz0PEDbrtd1tLYoO0hukW5PSa6eHykch0Hc6etiqEx1xziS+vNf+iOXds70I4htaYit6yRToZlQ
30
+ Mim3DQxaZX68nIHIZogur0zGv9U8j01v5l/rHRxyDdlVx3+JkBg6Cqx4U1PXEnAJriqcyg0B8Gm
31
+ V8Lnmfng+aJLRyq5MkhstYCRv9AsmWu8NpZDJ1ffbkaS02Z9/wpubXTiFP6DG3V2mDw2VvzEcHi
32
+ cchw49oXmTi92yui+kBgSYlNygssOAyU6H071AfmRUeH3+TsV5u5rg+bCiKyHemVmcKdd3hhZB+
33
+ HjA8o3On6rg5wIDAQAB""".replace(" ", "")
34
+
35
+ PUBLIC_KEY_TEST = """MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC1nAzH31arNBmYKvTlvKgkxI1MIr4HpfLbmM
36
+ XPIhd8D/cXB0dYY1ppUq4a/ezq41YShN88e0elyZgqdnFrkhiLpnKWa7jXtVRgXi9eS18PLO8ns
37
+ eHude9URaj7relK1AZ0xovKsbLKHd01PpmngLXZfnKA06J2ru/zH+cnpXdy8QIDAQAB""".replace(" ", "")
38
+
39
+ def __init__(self) -> None:
40
+ self.AES_PASW = self.get_aes_key() # Get from previous implementation
41
+ self.IV = self.get_iv() # Get from previous implementation
42
+ self._public_key = self.load_public_key()
43
+ self._private_key = self.load_private_key()
44
+
45
+ @staticmethod
46
+ def load_private_key():
47
+ """Load the private key from base64 encoded string"""
48
+ try:
49
+ private_key_bytes = base64.b64decode(EncryptionUtils.PRIVATE_KEY)
50
+ return serialization.load_der_private_key(private_key_bytes, password=None, backend=default_backend())
51
+ except Exception as e:
52
+ raise Exception(f"Failed to load private key: {e!s}")
53
+
54
+ @staticmethod
55
+ def load_public_key(is_production: bool = True):
56
+ """Load the public key from base64 encoded string
57
+
58
+ Args:
59
+ is_production (bool): If True, uses production key, else uses test key
60
+
61
+ """
62
+ try:
63
+ key_string = EncryptionUtils.PUBLIC_KEY_PROD if is_production else EncryptionUtils.PUBLIC_KEY_TEST
64
+ public_key_bytes = base64.b64decode(key_string)
65
+ return serialization.load_der_public_key(public_key_bytes, backend=default_backend())
66
+ except Exception as e:
67
+ raise Exception(f"Failed to load public key: {e!s}")
68
+
69
+ @staticmethod
70
+ def encrypt(plaintext: str, key: str, iv: str) -> str:
71
+ """Encrypt text using AES/CBC/PKCS5Padding
72
+
73
+ Args:
74
+ plaintext (str): Text to encrypt
75
+ key (str): Encryption key
76
+ iv (str): Initialization vector
77
+
78
+ Returns:
79
+ str: Base64 encoded encrypted string
80
+
81
+ Raises:
82
+ Exception: If encryption fails
83
+
84
+ """
85
+ try:
86
+ # Convert strings to bytes
87
+ plaintext_bytes = plaintext.encode("utf-8")
88
+ key_bytes = key.encode("utf-8")
89
+ iv_bytes = iv.encode("utf-8")
90
+
91
+ # Create padder
92
+ padder = padding.PKCS7(128).padder()
93
+ padded_data = padder.update(plaintext_bytes) + padder.finalize()
94
+
95
+ # Create cipher
96
+ cipher = Cipher(algorithms.AES(key_bytes), modes.CBC(iv_bytes), backend=default_backend())
97
+
98
+ # Encrypt
99
+ encryptor = cipher.encryptor()
100
+ encrypted_bytes = encryptor.update(padded_data) + encryptor.finalize()
101
+
102
+ # Encode to base64
103
+ return base64.b64encode(encrypted_bytes).decode("utf-8")
104
+
105
+ except Exception as e:
106
+ raise Exception(f"Encryption failed: {e!s}")
107
+
108
+ def encryption_by_aes(self, text: str) -> str:
109
+ """Encrypt text using AES with class-level key and IV
110
+
111
+ Args:
112
+ text (str): Text to encrypt
113
+
114
+ Returns:
115
+ str: Encrypted text or None if encryption fails
116
+
117
+ """
118
+ try:
119
+ # Perform encryption
120
+ encrypted = self.encrypt(text, self.AES_PASW, self.IV)
121
+
122
+ return encrypted
123
+
124
+ except Exception as e:
125
+ _LOGGER.error(f"Encryption failed: {e!s}")
126
+ return None
127
+
128
+ def encrypt_by_public_key(self) -> str | None:
129
+ """Encrypt data using RSA public key.
130
+
131
+ Args:
132
+
133
+ Returns:
134
+ Optional[str]: Base64 encoded encrypted data or None if encryption fails
135
+
136
+ """
137
+
138
+ data = f"{self.AES_PASW},{self.IV}"
139
+
140
+ if not self._public_key:
141
+ _LOGGER.error("Public key not initialized")
142
+ return None
143
+
144
+ try:
145
+ # Convert input string to bytes
146
+ data_bytes = data.encode("utf-8")
147
+
148
+ # Encrypt the data padding.PKCS7(128).padder()
149
+ encrypted_bytes = self._public_key.encrypt(data_bytes, rsa_padding.PKCS1v15())
150
+
151
+ # Convert to base64 string
152
+ encrypted_str = base64.b64encode(encrypted_bytes).decode("utf-8")
153
+ _LOGGER.debug("Data encrypted successfully")
154
+
155
+ return encrypted_str
156
+
157
+ except Exception as err:
158
+ _LOGGER.error("Encryption failed: %s", str(err))
159
+ return None
160
+
161
+ @staticmethod
162
+ def get_random_string(length: int) -> str:
163
+ """Generate a random string of specified length using alphanumeric characters.
164
+
165
+ Args:
166
+ length (int): The desired length of the random string
167
+
168
+ Returns:
169
+ str: A random alphanumeric string of specified length
170
+
171
+ Raises:
172
+ ValueError: If length is less than 1
173
+
174
+ """
175
+ if length < 1:
176
+ raise ValueError("Length must be positive")
177
+
178
+ charset = string.ascii_letters + string.digits
179
+ return "".join(secrets.choice(charset) for _ in range(length))
180
+
181
+ @staticmethod
182
+ def get_random_int(length: int) -> str:
183
+ """Generate a random string of specified length containing only digits.
184
+
185
+ Args:
186
+ length (int): The desired length of the random number string
187
+
188
+ Returns:
189
+ str: A string of random digits of specified length
190
+
191
+ Raises:
192
+ ValueError: If length is less than 1
193
+
194
+ """
195
+ if length < 1:
196
+ raise ValueError("Length must be positive")
197
+
198
+ return "".join(secrets.choice(string.digits) for _ in range(length))
199
+
200
+ @staticmethod
201
+ def get_aes_key() -> str:
202
+ """Generate a random AES key of 16 characters using alphanumeric characters.
203
+ Matches Java implementation behavior.
204
+
205
+ Returns:
206
+ str: A 16-character random string for AES key
207
+
208
+ """
209
+ return EncryptionUtils.get_random_string(16)
210
+
211
+ @staticmethod
212
+ def get_iv() -> str:
213
+ """Generate a random initialization vector of 16 digits.
214
+ Matches Java implementation behavior.
215
+
216
+ Returns:
217
+ str: A 16-digit random string for initialization vector
218
+
219
+ """
220
+ return EncryptionUtils.get_random_int(16)