matterbridge-roborock-vacuum-plugin-regions 1.1.1-jb.1

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 (261) hide show
  1. package/.github/workflows/build.yml +56 -0
  2. package/.github/workflows/coverage.yml +59 -0
  3. package/.github/workflows/publish.yml +37 -0
  4. package/.tarignore +5 -0
  5. package/CHANGELOG.md +62 -0
  6. package/LICENSE +202 -0
  7. package/README.md +135 -0
  8. package/README_CLEANMODE.md +29 -0
  9. package/README_DEV.md +75 -0
  10. package/README_REPORT_ISSUE.md +34 -0
  11. package/README_SUPPORTED.md +67 -0
  12. package/dist/behaviorFactory.js +26 -0
  13. package/dist/behaviors/BehaviorDeviceGeneric.js +22 -0
  14. package/dist/behaviors/roborock.vacuum/default/default.js +183 -0
  15. package/dist/behaviors/roborock.vacuum/default/initalData.js +143 -0
  16. package/dist/behaviors/roborock.vacuum/default/runtimes.js +21 -0
  17. package/dist/behaviors/roborock.vacuum/smart/initalData.js +18 -0
  18. package/dist/behaviors/roborock.vacuum/smart/runtimes.js +11 -0
  19. package/dist/behaviors/roborock.vacuum/smart/smart.js +119 -0
  20. package/dist/clientManager.js +17 -0
  21. package/dist/helper.js +76 -0
  22. package/dist/index.js +4 -0
  23. package/dist/initialData/getBatteryStatus.js +24 -0
  24. package/dist/initialData/getOperationalStates.js +82 -0
  25. package/dist/initialData/getSupportedAreas.js +120 -0
  26. package/dist/initialData/getSupportedCleanModes.js +17 -0
  27. package/dist/initialData/getSupportedRunModes.js +11 -0
  28. package/dist/initialData/getSupportedScenes.js +26 -0
  29. package/dist/initialData/index.js +6 -0
  30. package/dist/model/CloudMessageModel.js +1 -0
  31. package/dist/model/DockingStationStatus.js +26 -0
  32. package/dist/model/ExperimentalFeatureSetting.js +30 -0
  33. package/dist/model/RoomMap.js +19 -0
  34. package/dist/model/roomIndexMap.js +21 -0
  35. package/dist/notifyMessageTypes.js +9 -0
  36. package/dist/platform.js +312 -0
  37. package/dist/platformRunner.js +90 -0
  38. package/dist/roborockCommunication/RESTAPI/roborockAuthenticateApi.js +213 -0
  39. package/dist/roborockCommunication/RESTAPI/roborockIoTApi.js +95 -0
  40. package/dist/roborockCommunication/Zenum/additionalPropCode.js +4 -0
  41. package/dist/roborockCommunication/Zenum/authenticateResponseCode.js +7 -0
  42. package/dist/roborockCommunication/Zenum/dockType.js +4 -0
  43. package/dist/roborockCommunication/Zenum/operationStatusCode.js +44 -0
  44. package/dist/roborockCommunication/Zenum/vacuumAndDockErrorCode.js +68 -0
  45. package/dist/roborockCommunication/Zmodel/apiResponse.js +1 -0
  46. package/dist/roborockCommunication/Zmodel/authenticateFlowState.js +1 -0
  47. package/dist/roborockCommunication/Zmodel/authenticateResponse.js +1 -0
  48. package/dist/roborockCommunication/Zmodel/baseURL.js +1 -0
  49. package/dist/roborockCommunication/Zmodel/batteryMessage.js +1 -0
  50. package/dist/roborockCommunication/Zmodel/device.js +1 -0
  51. package/dist/roborockCommunication/Zmodel/deviceModel.js +28 -0
  52. package/dist/roborockCommunication/Zmodel/deviceSchema.js +1 -0
  53. package/dist/roborockCommunication/Zmodel/deviceStatus.js +22 -0
  54. package/dist/roborockCommunication/Zmodel/dockInfo.js +6 -0
  55. package/dist/roborockCommunication/Zmodel/home.js +1 -0
  56. package/dist/roborockCommunication/Zmodel/homeInfo.js +1 -0
  57. package/dist/roborockCommunication/Zmodel/map.js +1 -0
  58. package/dist/roborockCommunication/Zmodel/mapInfo.js +29 -0
  59. package/dist/roborockCommunication/Zmodel/messageResult.js +7 -0
  60. package/dist/roborockCommunication/Zmodel/multipleMap.js +1 -0
  61. package/dist/roborockCommunication/Zmodel/networkInfo.js +1 -0
  62. package/dist/roborockCommunication/Zmodel/product.js +1 -0
  63. package/dist/roborockCommunication/Zmodel/room.js +1 -0
  64. package/dist/roborockCommunication/Zmodel/roomInfo.js +22 -0
  65. package/dist/roborockCommunication/Zmodel/scene.js +16 -0
  66. package/dist/roborockCommunication/Zmodel/userData.js +1 -0
  67. package/dist/roborockCommunication/Zmodel/vacuumError.js +27 -0
  68. package/dist/roborockCommunication/broadcast/abstractClient.js +55 -0
  69. package/dist/roborockCommunication/broadcast/client/LocalNetworkClient.js +174 -0
  70. package/dist/roborockCommunication/broadcast/client/LocalNetworkUDPClient.js +129 -0
  71. package/dist/roborockCommunication/broadcast/client/MQTTClient.js +139 -0
  72. package/dist/roborockCommunication/broadcast/client.js +1 -0
  73. package/dist/roborockCommunication/broadcast/clientRouter.js +82 -0
  74. package/dist/roborockCommunication/broadcast/listener/abstractConnectionListener.js +1 -0
  75. package/dist/roborockCommunication/broadcast/listener/abstractMessageHandler.js +1 -0
  76. package/dist/roborockCommunication/broadcast/listener/abstractMessageListener.js +1 -0
  77. package/dist/roborockCommunication/broadcast/listener/implementation/chainedConnectionListener.js +26 -0
  78. package/dist/roborockCommunication/broadcast/listener/implementation/chainedMessageListener.js +11 -0
  79. package/dist/roborockCommunication/broadcast/listener/implementation/connectionStateListener.js +43 -0
  80. package/dist/roborockCommunication/broadcast/listener/implementation/generalSyncMessageListener.js +28 -0
  81. package/dist/roborockCommunication/broadcast/listener/implementation/simpleMessageListener.js +27 -0
  82. package/dist/roborockCommunication/broadcast/listener/implementation/syncMessageListener.js +33 -0
  83. package/dist/roborockCommunication/broadcast/listener/index.js +1 -0
  84. package/dist/roborockCommunication/broadcast/messageProcessor.js +148 -0
  85. package/dist/roborockCommunication/broadcast/model/contentMessage.js +1 -0
  86. package/dist/roborockCommunication/broadcast/model/dps.js +1 -0
  87. package/dist/roborockCommunication/broadcast/model/headerMessage.js +1 -0
  88. package/dist/roborockCommunication/broadcast/model/messageContext.js +37 -0
  89. package/dist/roborockCommunication/broadcast/model/protocol.js +28 -0
  90. package/dist/roborockCommunication/broadcast/model/requestMessage.js +38 -0
  91. package/dist/roborockCommunication/broadcast/model/responseMessage.js +14 -0
  92. package/dist/roborockCommunication/helper/chunkBuffer.js +17 -0
  93. package/dist/roborockCommunication/helper/cryptoHelper.js +23 -0
  94. package/dist/roborockCommunication/helper/messageDeserializer.js +98 -0
  95. package/dist/roborockCommunication/helper/messageSerializer.js +84 -0
  96. package/dist/roborockCommunication/helper/nameDecoder.js +66 -0
  97. package/dist/roborockCommunication/helper/sequence.js +16 -0
  98. package/dist/roborockCommunication/index.js +13 -0
  99. package/dist/roborockService.js +494 -0
  100. package/dist/runtimes/handleCloudMessage.js +110 -0
  101. package/dist/runtimes/handleHomeDataMessage.js +57 -0
  102. package/dist/runtimes/handleLocalMessage.js +169 -0
  103. package/dist/rvc.js +51 -0
  104. package/dist/settings.js +1 -0
  105. package/dist/share/function.js +93 -0
  106. package/dist/share/runtimeHelper.js +17 -0
  107. package/dist/tests/testData/mockData.js +359 -0
  108. package/eslint.config.js +80 -0
  109. package/jest.config.js +22 -0
  110. package/jest.setup.js +2 -0
  111. package/logo.png +0 -0
  112. package/matterbridge-roborock-vacuum-plugin.config.json +46 -0
  113. package/matterbridge-roborock-vacuum-plugin.schema.json +293 -0
  114. package/misc/status.md +119 -0
  115. package/package.json +111 -0
  116. package/prettier.config.js +49 -0
  117. package/screenshot/IMG_1.PNG +0 -0
  118. package/screenshot/IMG_2.PNG +0 -0
  119. package/screenshot/IMG_3.PNG +0 -0
  120. package/screenshot/IMG_4.PNG +0 -0
  121. package/screenshot/IMG_5.PNG +0 -0
  122. package/screenshot/IMG_6.PNG +0 -0
  123. package/screenshot/IMG_7.PNG +0 -0
  124. package/src/behaviorFactory.ts +41 -0
  125. package/src/behaviors/BehaviorDeviceGeneric.ts +31 -0
  126. package/src/behaviors/roborock.vacuum/default/default.ts +238 -0
  127. package/src/behaviors/roborock.vacuum/default/initalData.ts +152 -0
  128. package/src/behaviors/roborock.vacuum/default/runtimes.ts +23 -0
  129. package/src/behaviors/roborock.vacuum/smart/initalData.ts +20 -0
  130. package/src/behaviors/roborock.vacuum/smart/runtimes.ts +15 -0
  131. package/src/behaviors/roborock.vacuum/smart/smart.ts +159 -0
  132. package/src/clientManager.ts +23 -0
  133. package/src/helper.ts +97 -0
  134. package/src/index.ts +16 -0
  135. package/src/initialData/getBatteryStatus.ts +26 -0
  136. package/src/initialData/getOperationalStates.ts +94 -0
  137. package/src/initialData/getSupportedAreas.ts +162 -0
  138. package/src/initialData/getSupportedCleanModes.ts +22 -0
  139. package/src/initialData/getSupportedRunModes.ts +14 -0
  140. package/src/initialData/getSupportedScenes.ts +32 -0
  141. package/src/initialData/index.ts +6 -0
  142. package/src/model/CloudMessageModel.ts +11 -0
  143. package/src/model/DockingStationStatus.ts +41 -0
  144. package/src/model/ExperimentalFeatureSetting.ts +77 -0
  145. package/src/model/RoomMap.ts +38 -0
  146. package/src/model/roomIndexMap.ts +26 -0
  147. package/src/notifyMessageTypes.ts +8 -0
  148. package/src/platform.ts +424 -0
  149. package/src/platformRunner.ts +103 -0
  150. package/src/roborockCommunication/RESTAPI/roborockAuthenticateApi.ts +302 -0
  151. package/src/roborockCommunication/RESTAPI/roborockIoTApi.ts +107 -0
  152. package/src/roborockCommunication/Zenum/additionalPropCode.ts +3 -0
  153. package/src/roborockCommunication/Zenum/authenticateResponseCode.ts +6 -0
  154. package/src/roborockCommunication/Zenum/dockType.ts +3 -0
  155. package/src/roborockCommunication/Zenum/operationStatusCode.ts +43 -0
  156. package/src/roborockCommunication/Zenum/vacuumAndDockErrorCode.ts +68 -0
  157. package/src/roborockCommunication/Zmodel/apiResponse.ts +3 -0
  158. package/src/roborockCommunication/Zmodel/authenticateFlowState.ts +6 -0
  159. package/src/roborockCommunication/Zmodel/authenticateResponse.ts +5 -0
  160. package/src/roborockCommunication/Zmodel/baseURL.ts +5 -0
  161. package/src/roborockCommunication/Zmodel/batteryMessage.ts +16 -0
  162. package/src/roborockCommunication/Zmodel/device.ts +50 -0
  163. package/src/roborockCommunication/Zmodel/deviceModel.ts +27 -0
  164. package/src/roborockCommunication/Zmodel/deviceSchema.ts +8 -0
  165. package/src/roborockCommunication/Zmodel/deviceStatus.ts +30 -0
  166. package/src/roborockCommunication/Zmodel/dockInfo.ts +9 -0
  167. package/src/roborockCommunication/Zmodel/home.ts +13 -0
  168. package/src/roborockCommunication/Zmodel/homeInfo.ts +5 -0
  169. package/src/roborockCommunication/Zmodel/map.ts +20 -0
  170. package/src/roborockCommunication/Zmodel/mapInfo.ts +54 -0
  171. package/src/roborockCommunication/Zmodel/messageResult.ts +75 -0
  172. package/src/roborockCommunication/Zmodel/multipleMap.ts +8 -0
  173. package/src/roborockCommunication/Zmodel/networkInfo.ts +7 -0
  174. package/src/roborockCommunication/Zmodel/product.ts +9 -0
  175. package/src/roborockCommunication/Zmodel/room.ts +4 -0
  176. package/src/roborockCommunication/Zmodel/roomInfo.ts +30 -0
  177. package/src/roborockCommunication/Zmodel/scene.ts +44 -0
  178. package/src/roborockCommunication/Zmodel/userData.ts +26 -0
  179. package/src/roborockCommunication/Zmodel/vacuumError.ts +35 -0
  180. package/src/roborockCommunication/broadcast/abstractClient.ts +80 -0
  181. package/src/roborockCommunication/broadcast/client/LocalNetworkClient.ts +218 -0
  182. package/src/roborockCommunication/broadcast/client/LocalNetworkUDPClient.ts +157 -0
  183. package/src/roborockCommunication/broadcast/client/MQTTClient.ts +174 -0
  184. package/src/roborockCommunication/broadcast/client.ts +19 -0
  185. package/src/roborockCommunication/broadcast/clientRouter.ts +104 -0
  186. package/src/roborockCommunication/broadcast/listener/abstractConnectionListener.ts +6 -0
  187. package/src/roborockCommunication/broadcast/listener/abstractMessageHandler.ts +11 -0
  188. package/src/roborockCommunication/broadcast/listener/abstractMessageListener.ts +5 -0
  189. package/src/roborockCommunication/broadcast/listener/implementation/chainedConnectionListener.ts +33 -0
  190. package/src/roborockCommunication/broadcast/listener/implementation/chainedMessageListener.ts +16 -0
  191. package/src/roborockCommunication/broadcast/listener/implementation/connectionStateListener.ts +57 -0
  192. package/src/roborockCommunication/broadcast/listener/implementation/generalSyncMessageListener.ts +38 -0
  193. package/src/roborockCommunication/broadcast/listener/implementation/simpleMessageListener.ts +37 -0
  194. package/src/roborockCommunication/broadcast/listener/implementation/syncMessageListener.ts +50 -0
  195. package/src/roborockCommunication/broadcast/listener/index.ts +3 -0
  196. package/src/roborockCommunication/broadcast/messageProcessor.ts +184 -0
  197. package/src/roborockCommunication/broadcast/model/contentMessage.ts +5 -0
  198. package/src/roborockCommunication/broadcast/model/dps.ts +19 -0
  199. package/src/roborockCommunication/broadcast/model/headerMessage.ts +7 -0
  200. package/src/roborockCommunication/broadcast/model/messageContext.ts +53 -0
  201. package/src/roborockCommunication/broadcast/model/protocol.ts +28 -0
  202. package/src/roborockCommunication/broadcast/model/requestMessage.ts +51 -0
  203. package/src/roborockCommunication/broadcast/model/responseMessage.ts +19 -0
  204. package/src/roborockCommunication/helper/chunkBuffer.ts +18 -0
  205. package/src/roborockCommunication/helper/cryptoHelper.ts +30 -0
  206. package/src/roborockCommunication/helper/messageDeserializer.ts +119 -0
  207. package/src/roborockCommunication/helper/messageSerializer.ts +101 -0
  208. package/src/roborockCommunication/helper/nameDecoder.ts +78 -0
  209. package/src/roborockCommunication/helper/sequence.ts +18 -0
  210. package/src/roborockCommunication/index.ts +25 -0
  211. package/src/roborockService.ts +657 -0
  212. package/src/runtimes/handleCloudMessage.ts +134 -0
  213. package/src/runtimes/handleHomeDataMessage.ts +67 -0
  214. package/src/runtimes/handleLocalMessage.ts +209 -0
  215. package/src/rvc.ts +97 -0
  216. package/src/settings.ts +1 -0
  217. package/src/share/function.ts +103 -0
  218. package/src/share/runtimeHelper.ts +23 -0
  219. package/src/tests/behaviors/roborock.vacuum/default/default.test.ts +134 -0
  220. package/src/tests/behaviors/roborock.vacuum/smart/runtimes.test.ts +64 -0
  221. package/src/tests/behaviors/roborock.vacuum/smart/smart.test.ts +215 -0
  222. package/src/tests/helper.test.ts +162 -0
  223. package/src/tests/initialData/getSupportedAreas.test.ts +181 -0
  224. package/src/tests/model/DockingStationStatus.test.ts +39 -0
  225. package/src/tests/platformRunner.test.ts +188 -0
  226. package/src/tests/platformRunner2.test.ts +228 -0
  227. package/src/tests/platformRunner3.test.ts +46 -0
  228. package/src/tests/roborockCommunication/RESTAPI/roborockAuthenticateApi.test.ts +144 -0
  229. package/src/tests/roborockCommunication/RESTAPI/roborockIoTApi.test.ts +106 -0
  230. package/src/tests/roborockCommunication/broadcast/client/LocalNetworkClient.test.ts +189 -0
  231. package/src/tests/roborockCommunication/broadcast/client/MQTTClient.test.ts +208 -0
  232. package/src/tests/roborockCommunication/broadcast/clientRouter.test.ts +168 -0
  233. package/src/tests/roborockCommunication/broadcast/listener/implementation/chainedConnectionListener.test.ts +59 -0
  234. package/src/tests/roborockCommunication/broadcast/listener/implementation/chainedMessageListener.test.ts +46 -0
  235. package/src/tests/roborockCommunication/broadcast/listener/implementation/simpleMessageListener.test.ts +71 -0
  236. package/src/tests/roborockCommunication/broadcast/listener/implementation/syncMessageListener.test.ts +86 -0
  237. package/src/tests/roborockCommunication/broadcast/messageProcessor.test.ts +126 -0
  238. package/src/tests/roborockService.setSelectedAreas.test.ts +61 -0
  239. package/src/tests/roborockService.test.ts +517 -0
  240. package/src/tests/roborockService2.test.ts +69 -0
  241. package/src/tests/roborockService3.test.ts +133 -0
  242. package/src/tests/roborockService4.test.ts +76 -0
  243. package/src/tests/roborockService5.test.ts +79 -0
  244. package/src/tests/runtimes/handleCloudMessage.test.ts +200 -0
  245. package/src/tests/runtimes/handleHomeDataMessage.test.ts +54 -0
  246. package/src/tests/runtimes/handleLocalMessage.test.ts +227 -0
  247. package/src/tests/testData/mockData.ts +370 -0
  248. package/src/tests/testData/mockHomeData-a187.json +286 -0
  249. package/tsconfig.jest.json +21 -0
  250. package/tsconfig.json +37 -0
  251. package/tsconfig.production.json +19 -0
  252. package/tslint.json +9 -0
  253. package/web-for-testing/README.md +47 -0
  254. package/web-for-testing/nodemon.json +7 -0
  255. package/web-for-testing/package-lock.json +6600 -0
  256. package/web-for-testing/package.json +36 -0
  257. package/web-for-testing/src/app.ts +194 -0
  258. package/web-for-testing/tsconfig-ext.json +19 -0
  259. package/web-for-testing/tsconfig.json +23 -0
  260. package/web-for-testing/views/index.ejs +172 -0
  261. package/web-for-testing/watch.mjs +93 -0
@@ -0,0 +1,30 @@
1
+ import { VacuumErrorCode, DockErrorCode } from '../Zenum/vacuumAndDockErrorCode.js';
2
+ import { DockInfo } from './dockInfo.js';
3
+ import { CloudMessageResult } from './messageResult.js';
4
+ import { VacuumError } from './vacuumError.js';
5
+
6
+ export class DeviceStatus {
7
+ errorStatus: VacuumError;
8
+ message: CloudMessageResult;
9
+
10
+ constructor(message: CloudMessageResult[]) {
11
+ this.message = message[0];
12
+ this.errorStatus = new VacuumError(this.message.error_code, this.message.dock_error_status);
13
+ }
14
+
15
+ getBattery(): number {
16
+ return this.message.battery;
17
+ }
18
+
19
+ getVacuumErrorCode(): VacuumErrorCode {
20
+ return this.message.error_code;
21
+ }
22
+
23
+ getDockInfo(): DockInfo {
24
+ return new DockInfo(this.message.dock_type);
25
+ }
26
+
27
+ getDockErrorCode(): DockErrorCode {
28
+ return this.message.dock_error_status;
29
+ }
30
+ }
@@ -0,0 +1,9 @@
1
+ import { DockType } from '../Zenum/dockType.js';
2
+
3
+ export class DockInfo {
4
+ private readonly dockType: DockType;
5
+
6
+ constructor(dockType: DockType) {
7
+ this.dockType = dockType;
8
+ }
9
+ }
@@ -0,0 +1,13 @@
1
+ import { Device } from './device.js';
2
+ import { Product } from './product.js';
3
+ import { Room } from './room.js';
4
+
5
+ export interface Home {
6
+ id: number;
7
+ name: string;
8
+
9
+ products: Product[];
10
+ devices: Device[];
11
+ receivedDevices: Device[];
12
+ rooms: Room[];
13
+ }
@@ -0,0 +1,5 @@
1
+ export interface HomeInfo {
2
+ id: number;
3
+ name: string;
4
+ rrHomeId: number;
5
+ }
@@ -0,0 +1,20 @@
1
+ interface MapBackupInformation {
2
+ mapFlag: number;
3
+ add_time: number;
4
+ }
5
+
6
+ export interface MapInformation {
7
+ mapFlag: number;
8
+ add_time: number;
9
+ length: number;
10
+ name: string;
11
+ rooms?: RoomInformation[] | undefined;
12
+ bak_maps: MapBackupInformation[];
13
+ }
14
+
15
+ export interface RoomInformation {
16
+ id: number;
17
+ tag: number;
18
+ iot_name_id: string;
19
+ iot_name: string;
20
+ }
@@ -0,0 +1,54 @@
1
+ import decodeComponent from '../helper/nameDecoder.js';
2
+ import { RoomInformation } from './map.js';
3
+ import type { MultipleMap } from './multipleMap.js';
4
+
5
+ export interface MapRoom {
6
+ id: number;
7
+ iot_name_id: string;
8
+ tag: number;
9
+ globalId?: number;
10
+ displayName?: string;
11
+ mapId?: number;
12
+ }
13
+
14
+ export interface MapEntry {
15
+ id: number;
16
+ name: string | undefined;
17
+ rooms: MapRoom[];
18
+ }
19
+
20
+ export class MapInfo {
21
+ public readonly maps: MapEntry[] = [];
22
+ public readonly allRooms: MapRoom[] = [];
23
+
24
+ constructor(multimap: MultipleMap) {
25
+ this.maps = multimap.map_info.map((mapInfo) => {
26
+ const rooms: MapRoom[] =
27
+ mapInfo.rooms?.map((room: RoomInformation) => ({
28
+ id: room.id,
29
+ globalId: parseInt(room.iot_name_id),
30
+ iot_name_id: room.iot_name_id,
31
+ tag: room.tag,
32
+ displayName: room.iot_name,
33
+ mapId: mapInfo.mapFlag,
34
+ })) ?? [];
35
+
36
+ this.allRooms.push(...rooms);
37
+ return {
38
+ id: mapInfo.mapFlag,
39
+ name: decodeComponent(mapInfo.name),
40
+ rooms,
41
+ };
42
+ });
43
+
44
+ // this.allRooms = this.allRooms.filter((room, index, self) => index === self.findIndex((r) => r.globalId === room.globalId));
45
+ }
46
+
47
+ getById(id: number): string | undefined {
48
+ return this.maps.find((m) => m.id === id)?.name;
49
+ }
50
+
51
+ getByName(name: string): number | undefined {
52
+ return this.maps.find((m) => m.name?.toLowerCase() === name.toLowerCase())?.id;
53
+ }
54
+ }
@@ -0,0 +1,75 @@
1
+ export interface CloudMessageResult {
2
+ msg_ver: number;
3
+ msg_seq: number;
4
+ state: number;
5
+ battery: number;
6
+ clean_time: number;
7
+ clean_area: number;
8
+ error_code: number;
9
+ map_present: number;
10
+ in_cleaning: number;
11
+ in_returning: number;
12
+ in_fresh_state: number;
13
+ lab_status: number;
14
+ water_box_status: number;
15
+ back_type?: number;
16
+ wash_phase?: number;
17
+ wash_ready?: number;
18
+ wash_status?: number;
19
+ fan_power: number;
20
+ dnd_enabled: number;
21
+ map_status: number;
22
+ is_locating: number;
23
+ lock_status: number;
24
+ water_box_mode: number;
25
+ distance_off: number;
26
+ water_box_carriage_status: number;
27
+ mop_forbidden_enable: number;
28
+ camera_status?: number;
29
+ is_exploring?: number;
30
+ adbumper_status: number[];
31
+ water_shortage_status?: number;
32
+ dock_type: number;
33
+ dust_collection_status: number;
34
+ auto_dust_collection: number;
35
+ avoid_count?: number;
36
+ mop_mode?: number;
37
+ debug_mode: number;
38
+ in_warmup?: number;
39
+ collision_avoid_status?: number;
40
+ switch_map_mode: number;
41
+ dock_error_status: number;
42
+ charge_status: number;
43
+ unsave_map_reason?: number;
44
+ unsave_map_flag?: number;
45
+ dry_status?: number;
46
+ rdt?: number;
47
+ clean_percent?: number;
48
+ extra_time?: number;
49
+ rss?: number;
50
+ dss?: number;
51
+ common_status?: number;
52
+ last_clean_t?: number;
53
+ replenish_mode?: number;
54
+ repeat?: number;
55
+ kct?: number;
56
+ subdivision_sets?: number;
57
+ cleaning_info?: CleanInformation;
58
+ exit_dock?: number;
59
+ seq_type?: number;
60
+ }
61
+
62
+ interface CleanInformation {
63
+ target_segment_id: number;
64
+ segment_id: number;
65
+ fan_power: number;
66
+ water_box_status: number;
67
+ mop_mode: number;
68
+ }
69
+
70
+ export enum CarpetCleanMode {
71
+ Avoid = 0,
72
+ Ignore = 2,
73
+ Cross = 3,
74
+ DynamicLift = 200, // TODO
75
+ }
@@ -0,0 +1,8 @@
1
+ import { MapInformation } from './map.js';
2
+
3
+ export interface MultipleMap {
4
+ max_multi_map: number;
5
+ max_bak_map: number;
6
+ multi_map_count: number;
7
+ map_info: MapInformation[];
8
+ }
@@ -0,0 +1,7 @@
1
+ export interface NetworkInfo {
2
+ ssid: string;
3
+ ip: string;
4
+ mac: string;
5
+ bssid: string;
6
+ rssi: number;
7
+ }
@@ -0,0 +1,9 @@
1
+ import { DeviceSchema } from './deviceSchema.js';
2
+
3
+ export interface Product {
4
+ id: string;
5
+ name: string;
6
+ model: string;
7
+ category: string;
8
+ schema: DeviceSchema[];
9
+ }
@@ -0,0 +1,4 @@
1
+ export interface Room {
2
+ id: number; // this is global id
3
+ name: string;
4
+ }
@@ -0,0 +1,30 @@
1
+ import decodeComponent from '../helper/nameDecoder.js';
2
+ import { Room } from './room.js';
3
+
4
+ interface RoomEntry {
5
+ id: number;
6
+ name: string | undefined;
7
+ }
8
+
9
+ export class RoomInfo {
10
+ readonly rooms: RoomEntry[] = [];
11
+
12
+ constructor(roomInfo: Room[], roomData: number[][]) {
13
+ this.rooms = roomData
14
+ .map((entry) => {
15
+ return { id: entry[0], globalId: entry[1] };
16
+ })
17
+ .map((entry) => {
18
+ return {
19
+ id: entry.id,
20
+ room: roomInfo.find((el) => el.id == entry.globalId),
21
+ };
22
+ })
23
+ .map((entry) => {
24
+ return {
25
+ id: entry.id,
26
+ name: decodeComponent(entry.room?.name)?.toLowerCase(),
27
+ };
28
+ });
29
+ }
30
+ }
@@ -0,0 +1,44 @@
1
+ export class Scene {
2
+ id: number | undefined;
3
+ name: string | undefined;
4
+ param: string | undefined;
5
+ enabled: boolean | undefined;
6
+ extra: unknown | undefined;
7
+ type: string | undefined;
8
+ }
9
+
10
+ interface ActionInformation {
11
+ type: string;
12
+ items: SceneItem[];
13
+ }
14
+
15
+ export interface SceneParam {
16
+ triggers: unknown[];
17
+ action: ActionInformation;
18
+ matchType: string;
19
+ }
20
+
21
+ export class SceneItem {
22
+ id: number | undefined;
23
+ type: string | undefined;
24
+ name: string | undefined;
25
+ entityId: string | undefined;
26
+ param: SceneCommand | undefined;
27
+ finishDpIds: number[] | undefined;
28
+ }
29
+
30
+ export interface SceneCommand {
31
+ id: number;
32
+ method: string;
33
+ params: SceneCommandParam[];
34
+ }
35
+
36
+ export interface SceneCommandParam {
37
+ fan_power: number;
38
+ water_box_mode: number;
39
+ mop_mode: number;
40
+ mop_template_id: number;
41
+ repeat: number;
42
+ auto_dustCollection: number;
43
+ source: number;
44
+ }
@@ -0,0 +1,26 @@
1
+ export interface UserData {
2
+ uid: string | number;
3
+ tokentype: string;
4
+ token: string;
5
+ rruid: string;
6
+ region: string;
7
+ countrycode: string;
8
+ country: string;
9
+ nickname: string;
10
+ rriot: Rriot;
11
+ }
12
+
13
+ interface r {
14
+ r: string;
15
+ a: string;
16
+ m: string;
17
+ l: string;
18
+ }
19
+
20
+ export interface Rriot {
21
+ u: string;
22
+ s: string;
23
+ h: string;
24
+ k: string;
25
+ r: r;
26
+ }
@@ -0,0 +1,35 @@
1
+ import { DockErrorCode, VacuumErrorCode } from '../Zenum/vacuumAndDockErrorCode.js';
2
+
3
+ export class VacuumError {
4
+ private readonly vacuumErrorCode: VacuumErrorCode;
5
+ private readonly dockErrorCode: DockErrorCode;
6
+
7
+ constructor(errorCode: VacuumErrorCode, dockErrorCode: DockErrorCode) {
8
+ this.vacuumErrorCode = errorCode;
9
+ this.dockErrorCode = dockErrorCode;
10
+ }
11
+
12
+ hasError() {
13
+ return this.vacuumErrorCode != 0 || this.dockErrorCode != 0;
14
+ }
15
+
16
+ isStuck(): boolean {
17
+ return this.vacuumErrorCode === VacuumErrorCode.RobotTrapped;
18
+ }
19
+
20
+ isBatteryLow(): boolean {
21
+ return this.vacuumErrorCode === VacuumErrorCode.LowBattery;
22
+ }
23
+
24
+ isBinFull(): boolean {
25
+ return this.vacuumErrorCode === VacuumErrorCode.CleanAutoEmptyDock || this.dockErrorCode == DockErrorCode.DuctBlockage;
26
+ }
27
+
28
+ isCleanWaterEmpty(): boolean {
29
+ return this.vacuumErrorCode === VacuumErrorCode.ClearWaterTankEmpty || this.dockErrorCode == DockErrorCode.WaterEmpty;
30
+ }
31
+
32
+ isWasteWaterFull(): boolean {
33
+ return this.dockErrorCode == DockErrorCode.WasteWaterTankFull;
34
+ }
35
+ }
@@ -0,0 +1,80 @@
1
+ import { AnsiLogger } from 'matterbridge/logger';
2
+ import { MessageDeserializer } from '../helper/messageDeserializer.js';
3
+ import { MessageSerializer } from '../helper/messageSerializer.js';
4
+ import { AbstractConnectionListener } from './listener/abstractConnectionListener.js';
5
+ import { AbstractMessageListener } from './listener/abstractMessageListener.js';
6
+ import { RequestMessage } from './model/requestMessage.js';
7
+ import { Client } from './client.js';
8
+ import { MessageContext } from './model/messageContext.js';
9
+ import { ChainedConnectionListener } from './listener/implementation/chainedConnectionListener.js';
10
+ import { ChainedMessageListener } from './listener/implementation/chainedMessageListener.js';
11
+ import { SyncMessageListener } from './listener/implementation/syncMessageListener.js';
12
+ import { ResponseMessage } from '../index.js';
13
+ import { ConnectionStateListener } from './listener/implementation/connectionStateListener.js';
14
+
15
+ export abstract class AbstractClient implements Client {
16
+ public isInDisconnectingStep = false;
17
+ public retryCount = 0;
18
+
19
+ protected readonly connectionListeners = new ChainedConnectionListener();
20
+ protected readonly messageListeners = new ChainedMessageListener();
21
+ protected readonly serializer: MessageSerializer;
22
+ protected readonly deserializer: MessageDeserializer;
23
+ protected readonly context: MessageContext;
24
+ protected connected = false;
25
+ protected logger: AnsiLogger;
26
+
27
+ protected abstract clientName: string;
28
+ protected abstract shouldReconnect: boolean;
29
+
30
+ private readonly syncMessageListener: SyncMessageListener;
31
+
32
+ protected constructor(logger: AnsiLogger, context: MessageContext) {
33
+ this.context = context;
34
+ this.serializer = new MessageSerializer(this.context, logger);
35
+ this.deserializer = new MessageDeserializer(this.context, logger);
36
+
37
+ this.syncMessageListener = new SyncMessageListener(logger);
38
+ this.messageListeners.register(this.syncMessageListener);
39
+ this.logger = logger;
40
+ }
41
+
42
+ protected initializeConnectionStateListener() {
43
+ const connectionStateListener = new ConnectionStateListener(this.logger, this, this.clientName, this.shouldReconnect);
44
+ this.connectionListeners.register(connectionStateListener);
45
+ }
46
+
47
+ abstract connect(): void;
48
+ abstract disconnect(): Promise<void>;
49
+ abstract send(duid: string, request: RequestMessage): Promise<void>;
50
+
51
+ public async get<T>(duid: string, request: RequestMessage): Promise<T | undefined> {
52
+ return new Promise<T>((resolve, reject) => {
53
+ this.syncMessageListener.waitFor(request.messageId, request, (response: ResponseMessage) => resolve(response as unknown as T), reject);
54
+ this.send(duid, request);
55
+ })
56
+ .then((result: T) => {
57
+ return result;
58
+ })
59
+ .catch((error: Error) => {
60
+ this.logger.error(error.message);
61
+ return undefined;
62
+ });
63
+ }
64
+
65
+ public registerDevice(duid: string, localKey: string, pv: string, nonce: number | undefined): void {
66
+ this.context.registerDevice(duid, localKey, pv, nonce);
67
+ }
68
+
69
+ public registerConnectionListener(listener: AbstractConnectionListener): void {
70
+ this.connectionListeners.register(listener);
71
+ }
72
+
73
+ public registerMessageListener(listener: AbstractMessageListener): void {
74
+ this.messageListeners.register(listener);
75
+ }
76
+
77
+ public isConnected() {
78
+ return this.connected;
79
+ }
80
+ }
@@ -0,0 +1,218 @@
1
+ import { Socket } from 'node:net';
2
+ import { clearInterval } from 'node:timers';
3
+ import { Protocol } from '../model/protocol.js';
4
+ import { RequestMessage } from '../model/requestMessage.js';
5
+ import { AnsiLogger, debugStringify } from 'matterbridge/logger';
6
+ import { AbstractClient } from '../abstractClient.js';
7
+ import { MessageContext } from '../model/messageContext.js';
8
+ import { Sequence } from '../../helper/sequence.js';
9
+ import { ChunkBuffer } from '../../helper/chunkBuffer.js';
10
+
11
+ export class LocalNetworkClient extends AbstractClient {
12
+ protected override clientName = 'LocalNetworkClient';
13
+ protected override shouldReconnect = true;
14
+
15
+ private socket: Socket | undefined = undefined;
16
+ private buffer: ChunkBuffer = new ChunkBuffer();
17
+ private messageIdSeq: Sequence;
18
+ private pingInterval?: NodeJS.Timeout;
19
+ private keepConnectionAliveInterval: NodeJS.Timeout | undefined = undefined;
20
+
21
+ public duid: string;
22
+ public ip: string;
23
+
24
+ constructor(logger: AnsiLogger, context: MessageContext, duid: string, ip: string) {
25
+ super(logger, context);
26
+ this.duid = duid;
27
+ this.ip = ip;
28
+ this.messageIdSeq = new Sequence(100000, 999999);
29
+
30
+ this.initializeConnectionStateListener();
31
+ }
32
+
33
+ public connect(): void {
34
+ if (this.socket) {
35
+ return; // Already connected
36
+ }
37
+
38
+ this.socket = new Socket();
39
+
40
+ // Socket event listeners
41
+ this.socket.on('close', this.onDisconnect.bind(this));
42
+ this.socket.on('end', this.onEnd.bind(this));
43
+ this.socket.on('error', this.onError.bind(this));
44
+ this.socket.on('connect', this.onConnect.bind(this));
45
+ this.socket.on('timeout', this.onTimeout.bind(this));
46
+
47
+ // Data event listener
48
+ this.socket.on('data', this.onMessage.bind(this));
49
+ this.socket.connect(58867, this.ip);
50
+
51
+ this.keepConnectionAlive();
52
+ }
53
+
54
+ public async disconnect(): Promise<void> {
55
+ if (!this.socket) {
56
+ return;
57
+ }
58
+
59
+ this.isInDisconnectingStep = true;
60
+
61
+ if (this.pingInterval) {
62
+ clearInterval(this.pingInterval);
63
+ }
64
+ this.socket.destroy();
65
+ this.socket = undefined;
66
+ }
67
+
68
+ public async send(duid: string, request: RequestMessage): Promise<void> {
69
+ if (!this.socket || !this.connected) {
70
+ this.logger.error(`${duid}: socket is not online, , ${debugStringify(request)}`);
71
+ return;
72
+ }
73
+
74
+ const localRequest = request.toLocalRequest();
75
+ const message = this.serializer.serialize(duid, localRequest);
76
+
77
+ this.logger.debug(`sending message ${message.messageId}, protocol:${localRequest.protocol}, method:${localRequest.method}, secure:${request.secure} to ${duid}`);
78
+ this.socket.write(this.wrapWithLengthData(message.buffer));
79
+ }
80
+
81
+ private async onConnect(): Promise<void> {
82
+ this.logger.debug(` [LocalNetworkClient]: ${this.duid} connected to ${this.ip}`);
83
+ this.logger.debug(` [LocalNetworkClient]: ${this.duid} socket writable: ${this.socket?.writable}, readable: ${this.socket?.readable}`);
84
+ this.connected = true;
85
+ this.retryCount = 0;
86
+
87
+ await this.sendHelloMessage();
88
+ this.pingInterval = setInterval(this.sendPingRequest.bind(this), 5000);
89
+ await this.connectionListeners.onConnected(this.duid);
90
+ }
91
+
92
+ private async onDisconnect(hadError: boolean): Promise<void> {
93
+ this.logger.info(` [LocalNetworkClient]: ${this.duid} socket disconnected. Had error: ${hadError}`);
94
+ this.connected = false;
95
+
96
+ if (this.socket) {
97
+ this.socket.destroy();
98
+ this.socket = undefined;
99
+ }
100
+ if (this.pingInterval) {
101
+ clearInterval(this.pingInterval);
102
+ }
103
+ await this.connectionListeners.onDisconnected(this.duid, 'Socket disconnected. Had no error.');
104
+ }
105
+
106
+ private async onError(error: Error): Promise<void> {
107
+ this.logger.error(` [LocalNetworkClient]: Socket error for ${this.duid}: ${error.message}`);
108
+ await this.connectionListeners.onError(this.duid, error.message);
109
+ }
110
+
111
+ private async onTimeout(): Promise<void> {
112
+ this.logger.error(` [LocalNetworkClient]: Socket for ${this.duid} timed out.`);
113
+ }
114
+
115
+ private async onEnd(): Promise<void> {
116
+ this.logger.debug(` [LocalNetworkClient]: ${this.duid} socket ended.`);
117
+ }
118
+
119
+ private async onMessage(message: Buffer): Promise<void> {
120
+ if (!this.socket) {
121
+ return;
122
+ }
123
+
124
+ if (!message || message.length == 0) {
125
+ this.logger.debug('LocalNetworkClient received empty message from socket.');
126
+ return;
127
+ }
128
+
129
+ try {
130
+ this.buffer.append(message);
131
+
132
+ const receivedBuffer = this.buffer.get();
133
+ if (!this.isMessageComplete(receivedBuffer)) {
134
+ return;
135
+ }
136
+ this.buffer.reset();
137
+
138
+ let offset = 0;
139
+ while (offset + 4 <= receivedBuffer.length) {
140
+ const segmentLength = receivedBuffer.readUInt32BE(offset);
141
+ if (segmentLength == 17) {
142
+ offset += 4 + segmentLength;
143
+ continue;
144
+ }
145
+
146
+ try {
147
+ const currentBuffer = receivedBuffer.subarray(offset + 4, offset + segmentLength + 4);
148
+ const response = this.deserializer.deserialize(this.duid, currentBuffer);
149
+ await this.messageListeners.onMessage(response);
150
+ } catch (error) {
151
+ this.logger.error('LocalNetworkClient: unable to process message with error: ' + error);
152
+ // unable to process message: TypeError: Cannot read properties of undefined (reading 'length')
153
+ }
154
+ offset += 4 + segmentLength;
155
+ }
156
+ } catch (error) {
157
+ this.logger.error('LocalNetworkClient: read socket buffer error: ' + error);
158
+ }
159
+ }
160
+
161
+ private isMessageComplete(buffer: Buffer): boolean {
162
+ let totalLength = 0;
163
+ let offset = 0;
164
+
165
+ while (offset + 4 <= buffer.length) {
166
+ const segmentLength = buffer.readUInt32BE(offset);
167
+ totalLength += 4 + segmentLength;
168
+ offset += 4 + segmentLength;
169
+
170
+ if (offset > buffer.length) {
171
+ return false;
172
+ }
173
+ }
174
+
175
+ return totalLength <= buffer.length;
176
+ }
177
+
178
+ private wrapWithLengthData(buffer: Buffer<ArrayBufferLike>): Buffer<ArrayBufferLike> {
179
+ const lengthBuffer = Buffer.alloc(4);
180
+ lengthBuffer.writeUInt32BE(buffer.length, 0);
181
+ return Buffer.concat([lengthBuffer, buffer]);
182
+ }
183
+
184
+ private async sendHelloMessage(): Promise<void> {
185
+ const request = new RequestMessage({
186
+ protocol: Protocol.hello_request,
187
+ messageId: this.messageIdSeq.next(),
188
+ nonce: this.context.nonce,
189
+ });
190
+
191
+ await this.send(this.duid, request);
192
+ }
193
+
194
+ private async sendPingRequest(): Promise<void> {
195
+ const request = new RequestMessage({
196
+ protocol: Protocol.ping_request,
197
+ messageId: this.messageIdSeq.next(),
198
+ });
199
+ await this.send(this.duid, request);
200
+ }
201
+
202
+ private keepConnectionAlive(): void {
203
+ if (this.keepConnectionAliveInterval) {
204
+ clearTimeout(this.keepConnectionAliveInterval);
205
+ this.keepConnectionAliveInterval.unref();
206
+ }
207
+
208
+ this.keepConnectionAliveInterval = setInterval(
209
+ () => {
210
+ if (this.socket === undefined || !this.connected || !this.socket.writable || this.socket.readable) {
211
+ this.logger.debug(` [LocalNetworkClient]: ${this.duid} socket is not writable or readable, reconnecting...`);
212
+ this.connect();
213
+ }
214
+ },
215
+ 60 * 60 * 1000,
216
+ );
217
+ }
218
+ }