├── .gitignore ├── LICENSE ├── README.md ├── examples ├── avoid-obstacle.ts ├── dance.ts ├── get-state.ts ├── move-forward.ts ├── move-joints.ts └── move-square.ts ├── package-lock.json ├── package.json ├── src ├── go1.ts └── mqtt │ ├── go1-mqtt.ts │ ├── go1-state.ts │ ├── message-handler.ts │ ├── receivers │ ├── bms-receiver.ts │ └── robot-receiver.ts │ └── topics.ts └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | 78 | # Next.js build output 79 | .next 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | dist 84 | 85 | # Gatsby files 86 | .cache/ 87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 88 | # https://nextjs.org/blog/next-9-1#public-directory-support 89 | # public 90 | 91 | # vuepress build output 92 | .vuepress/dist 93 | 94 | # Serverless directories 95 | .serverless/ 96 | 97 | # FuseBox cache 98 | .fusebox/ 99 | 100 | # DynamoDB Local files 101 | .dynamodb/ 102 | 103 | # TernJS port file 104 | .tern-port 105 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Dennis Baldwin, DroneBlocks 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # go1-js 2 | 3 | ## Node JS Library for Unitree Go1 4 | 5 | ### Note: users upgrading to version 0.1.4 or newer you must initialize Go1 like the following: 6 | 7 | ``` 8 | let dog = new Go1(); 9 | dog.init(); // version 0.1.4+ requirement 10 | dog.setMode(Go1Mode.walk); 11 | dog.goForward(0.25, 2000); 12 | ``` 13 | 14 | Take a look at the examples directory for more details. 15 | -------------------------------------------------------------------------------- /examples/avoid-obstacle.ts: -------------------------------------------------------------------------------- 1 | import { Go1, Go1Mode } from "../src/go1"; 2 | import { Go1State } from "../src/mqtt/go1-state"; 3 | 4 | let dog: Go1; 5 | 6 | function handleCollisionDetection(state: Go1State): void { 7 | const warningThreshold: number = 0.75; 8 | const frontWarning: number = state.robot.distanceWarning.front; 9 | const backWarning: number = state.robot.distanceWarning.back; 10 | const leftWarning: number = state.robot.distanceWarning.left; 11 | const rightWarning: number = state.robot.distanceWarning.right; 12 | 13 | console.log(`Current forward warning is: ${frontWarning}`); 14 | 15 | if (frontWarning > warningThreshold) { 16 | dog.setLedColor(255, 0, 0); 17 | dog.setMode(Go1Mode.standDown); 18 | } 19 | } 20 | 21 | async function main() { 22 | dog = new Go1(); 23 | dog.init(); 24 | dog.setLedColor(0, 255, 0); 25 | 26 | dog.on("go1StateChange", (state) => { 27 | handleCollisionDetection(state); 28 | }); 29 | 30 | // Manually walk Go1 towards a wall (be careful!) 31 | while (true) { 32 | await dog.wait(500); 33 | } 34 | } 35 | 36 | main(); 37 | -------------------------------------------------------------------------------- /examples/dance.ts: -------------------------------------------------------------------------------- 1 | import { Go1, Go1Mode } from "../src/go1"; 2 | 3 | let dog: Go1; 4 | 5 | async function main() { 6 | dog = new Go1(); 7 | dog.init(); 8 | 9 | await dog.wait(3000); 10 | 11 | dog.setMode(Go1Mode.stand); 12 | 13 | await dog.wait(1000); 14 | 15 | await dog.lookUp(0.5, 1000); 16 | await dog.lookDown(0.5, 1000); 17 | await dog.leanLeft(0.5, 1000); 18 | await dog.leanRight(0.5, 1000); 19 | await dog.twistLeft(0.5, 1000); 20 | await dog.twistRight(0.5, 1000); 21 | 22 | await dog.resetBody(); 23 | 24 | await dog.lookUp(1, 1000); 25 | await dog.lookDown(1, 1000); 26 | await dog.leanLeft(1, 1000); 27 | await dog.leanRight(1, 1000); 28 | await dog.twistLeft(1, 1000); 29 | await dog.twistRight(1, 1000); 30 | 31 | await dog.resetBody(); 32 | 33 | dog.setMode(Go1Mode.walk); 34 | 35 | console.log("done"); 36 | } 37 | 38 | main(); 39 | -------------------------------------------------------------------------------- /examples/get-state.ts: -------------------------------------------------------------------------------- 1 | import { Go1, Go1Mode } from "../src/go1"; 2 | import { Go1State } from "../src/mqtt/go1-state"; 3 | 4 | let dog: Go1; 5 | 6 | function handleBattery(state: Go1State): void { 7 | const batt: number = state.bms.soc; 8 | 9 | console.log(`battery is at ${batt}%`); 10 | 11 | if (batt >= 75) { 12 | dog.setLedColor(0, 255, 0); // green 13 | } else if (batt >= 50 && batt < 75) { 14 | dog.setLedColor(255, 127, 0); // orange 15 | } else if (batt < 25) { 16 | dog.setLedColor(255, 0, 0); // red 17 | } 18 | } 19 | 20 | async function main() { 21 | dog = new Go1(); 22 | 23 | dog.on("go1StateChange", (state) => { 24 | handleBattery(state); 25 | }); 26 | 27 | // Normally you would navigate Go1 around 28 | // this infinite loop is just to demonstrate 29 | // the battery handler above 30 | while (true) { 31 | dog.setMode(Go1Mode.standDown); 32 | await dog.wait(2000); 33 | dog.setMode(Go1Mode.standUp); 34 | await dog.wait(2000); 35 | } 36 | } 37 | 38 | main(); 39 | -------------------------------------------------------------------------------- /examples/move-forward.ts: -------------------------------------------------------------------------------- 1 | import { Go1, Go1Mode } from "../src/go1"; 2 | 3 | let dog = new Go1(); 4 | dog.init(); 5 | dog.setMode(Go1Mode.walk); 6 | dog.goForward(0.25, 2000); 7 | //dog.go(0, -0.25, -0.25, 1000); 8 | -------------------------------------------------------------------------------- /examples/move-joints.ts: -------------------------------------------------------------------------------- 1 | import { Go1, Go1Mode } from "../src/go1"; 2 | 3 | let dog = new Go1(); 4 | dog.init(); 5 | dog.setMode(Go1Mode.stand); 6 | 7 | async function run() { 8 | // Use direct methods for pose 9 | for (let i = 0; i < 2; i++) { 10 | console.log("extend up"); 11 | await dog.extendUp(1, 2000); 12 | console.log("squat down"); 13 | await dog.squatDown(1, 2000); 14 | } 15 | 16 | // Use generic pose method 17 | await dog.pose(-1, 0, 0, 0, 2000); // Lean left 18 | await dog.pose(1, 0, 0, 0, 2000); // Lean right 19 | await dog.resetBody(); 20 | await dog.pose(0, -1, 0, 0, 2000); // Twist left 21 | await dog.pose(0, 1, 0, 0, 2000); // Twist right 22 | await dog.resetBody(); 23 | await dog.pose(0, 0, -1, 0, 2000); // Look up 24 | await dog.pose(0, 0, 1, 0, 2000); // Look down 25 | await dog.resetBody(); 26 | await dog.pose(0, 0, 0, -1, 2000); // Squat down 27 | await dog.pose(0, 0, 0, 1, 2000); // Extend up 28 | } 29 | 30 | run(); 31 | -------------------------------------------------------------------------------- /examples/move-square.ts: -------------------------------------------------------------------------------- 1 | import { Go1, Go1Mode } from "../src/go1"; 2 | 3 | async function run() { 4 | let dog = new Go1(); 5 | dog.init(); 6 | dog.setMode(Go1Mode.walk); 7 | await dog.goForward(0.1, 2000); 8 | await dog.goRight(0.1, 2000); 9 | await dog.goBackward(0.1, 2000); 10 | await dog.goLeft(0.1, 2000); 11 | dog.disconnect(); 12 | console.log("done!"); 13 | } 14 | 15 | run(); 16 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@droneblocks/go1-js", 3 | "version": "0.0.3", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "@droneblocks/go1-js", 9 | "version": "0.0.3", 10 | "license": "MIT", 11 | "dependencies": { 12 | "mqtt": "^4.3.7" 13 | }, 14 | "devDependencies": { 15 | "@types/node": "^18.11.9", 16 | "@types/ws": "^8.5.3", 17 | "ts-node": "^10.9.1", 18 | "typescript": "^4.9.3" 19 | } 20 | }, 21 | "node_modules/@cspotcode/source-map-support": { 22 | "version": "0.8.1", 23 | "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", 24 | "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", 25 | "dev": true, 26 | "dependencies": { 27 | "@jridgewell/trace-mapping": "0.3.9" 28 | }, 29 | "engines": { 30 | "node": ">=12" 31 | } 32 | }, 33 | "node_modules/@jridgewell/resolve-uri": { 34 | "version": "3.1.0", 35 | "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", 36 | "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", 37 | "dev": true, 38 | "engines": { 39 | "node": ">=6.0.0" 40 | } 41 | }, 42 | "node_modules/@jridgewell/sourcemap-codec": { 43 | "version": "1.4.14", 44 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", 45 | "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", 46 | "dev": true 47 | }, 48 | "node_modules/@jridgewell/trace-mapping": { 49 | "version": "0.3.9", 50 | "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", 51 | "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", 52 | "dev": true, 53 | "dependencies": { 54 | "@jridgewell/resolve-uri": "^3.0.3", 55 | "@jridgewell/sourcemap-codec": "^1.4.10" 56 | } 57 | }, 58 | "node_modules/@tsconfig/node10": { 59 | "version": "1.0.9", 60 | "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", 61 | "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", 62 | "dev": true 63 | }, 64 | "node_modules/@tsconfig/node12": { 65 | "version": "1.0.11", 66 | "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", 67 | "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", 68 | "dev": true 69 | }, 70 | "node_modules/@tsconfig/node14": { 71 | "version": "1.0.3", 72 | "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", 73 | "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", 74 | "dev": true 75 | }, 76 | "node_modules/@tsconfig/node16": { 77 | "version": "1.0.3", 78 | "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", 79 | "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", 80 | "dev": true 81 | }, 82 | "node_modules/@types/node": { 83 | "version": "18.11.9", 84 | "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.9.tgz", 85 | "integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==", 86 | "dev": true 87 | }, 88 | "node_modules/@types/ws": { 89 | "version": "8.5.3", 90 | "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz", 91 | "integrity": "sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==", 92 | "dev": true, 93 | "dependencies": { 94 | "@types/node": "*" 95 | } 96 | }, 97 | "node_modules/acorn": { 98 | "version": "8.8.1", 99 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", 100 | "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", 101 | "dev": true, 102 | "bin": { 103 | "acorn": "bin/acorn" 104 | }, 105 | "engines": { 106 | "node": ">=0.4.0" 107 | } 108 | }, 109 | "node_modules/acorn-walk": { 110 | "version": "8.2.0", 111 | "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", 112 | "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", 113 | "dev": true, 114 | "engines": { 115 | "node": ">=0.4.0" 116 | } 117 | }, 118 | "node_modules/arg": { 119 | "version": "4.1.3", 120 | "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", 121 | "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", 122 | "dev": true 123 | }, 124 | "node_modules/balanced-match": { 125 | "version": "1.0.2", 126 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 127 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" 128 | }, 129 | "node_modules/base64-js": { 130 | "version": "1.5.1", 131 | "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", 132 | "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", 133 | "funding": [ 134 | { 135 | "type": "github", 136 | "url": "https://github.com/sponsors/feross" 137 | }, 138 | { 139 | "type": "patreon", 140 | "url": "https://www.patreon.com/feross" 141 | }, 142 | { 143 | "type": "consulting", 144 | "url": "https://feross.org/support" 145 | } 146 | ] 147 | }, 148 | "node_modules/bl": { 149 | "version": "4.1.0", 150 | "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", 151 | "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", 152 | "dependencies": { 153 | "buffer": "^5.5.0", 154 | "inherits": "^2.0.4", 155 | "readable-stream": "^3.4.0" 156 | } 157 | }, 158 | "node_modules/brace-expansion": { 159 | "version": "1.1.11", 160 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 161 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 162 | "dependencies": { 163 | "balanced-match": "^1.0.0", 164 | "concat-map": "0.0.1" 165 | } 166 | }, 167 | "node_modules/buffer": { 168 | "version": "5.7.1", 169 | "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", 170 | "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", 171 | "funding": [ 172 | { 173 | "type": "github", 174 | "url": "https://github.com/sponsors/feross" 175 | }, 176 | { 177 | "type": "patreon", 178 | "url": "https://www.patreon.com/feross" 179 | }, 180 | { 181 | "type": "consulting", 182 | "url": "https://feross.org/support" 183 | } 184 | ], 185 | "dependencies": { 186 | "base64-js": "^1.3.1", 187 | "ieee754": "^1.1.13" 188 | } 189 | }, 190 | "node_modules/buffer-from": { 191 | "version": "1.1.2", 192 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", 193 | "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" 194 | }, 195 | "node_modules/commist": { 196 | "version": "1.1.0", 197 | "resolved": "https://registry.npmjs.org/commist/-/commist-1.1.0.tgz", 198 | "integrity": "sha512-rraC8NXWOEjhADbZe9QBNzLAN5Q3fsTPQtBV+fEVj6xKIgDgNiEVE6ZNfHpZOqfQ21YUzfVNUXLOEZquYvQPPg==", 199 | "dependencies": { 200 | "leven": "^2.1.0", 201 | "minimist": "^1.1.0" 202 | } 203 | }, 204 | "node_modules/concat-map": { 205 | "version": "0.0.1", 206 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 207 | "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" 208 | }, 209 | "node_modules/concat-stream": { 210 | "version": "2.0.0", 211 | "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", 212 | "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", 213 | "engines": [ 214 | "node >= 6.0" 215 | ], 216 | "dependencies": { 217 | "buffer-from": "^1.0.0", 218 | "inherits": "^2.0.3", 219 | "readable-stream": "^3.0.2", 220 | "typedarray": "^0.0.6" 221 | } 222 | }, 223 | "node_modules/create-require": { 224 | "version": "1.1.1", 225 | "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", 226 | "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", 227 | "dev": true 228 | }, 229 | "node_modules/debug": { 230 | "version": "4.3.4", 231 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", 232 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", 233 | "dependencies": { 234 | "ms": "2.1.2" 235 | }, 236 | "engines": { 237 | "node": ">=6.0" 238 | }, 239 | "peerDependenciesMeta": { 240 | "supports-color": { 241 | "optional": true 242 | } 243 | } 244 | }, 245 | "node_modules/diff": { 246 | "version": "4.0.2", 247 | "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", 248 | "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", 249 | "dev": true, 250 | "engines": { 251 | "node": ">=0.3.1" 252 | } 253 | }, 254 | "node_modules/duplexify": { 255 | "version": "4.1.2", 256 | "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.2.tgz", 257 | "integrity": "sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw==", 258 | "dependencies": { 259 | "end-of-stream": "^1.4.1", 260 | "inherits": "^2.0.3", 261 | "readable-stream": "^3.1.1", 262 | "stream-shift": "^1.0.0" 263 | } 264 | }, 265 | "node_modules/end-of-stream": { 266 | "version": "1.4.4", 267 | "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", 268 | "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", 269 | "dependencies": { 270 | "once": "^1.4.0" 271 | } 272 | }, 273 | "node_modules/fs.realpath": { 274 | "version": "1.0.0", 275 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 276 | "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" 277 | }, 278 | "node_modules/glob": { 279 | "version": "7.2.3", 280 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", 281 | "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", 282 | "dependencies": { 283 | "fs.realpath": "^1.0.0", 284 | "inflight": "^1.0.4", 285 | "inherits": "2", 286 | "minimatch": "^3.1.1", 287 | "once": "^1.3.0", 288 | "path-is-absolute": "^1.0.0" 289 | }, 290 | "engines": { 291 | "node": "*" 292 | }, 293 | "funding": { 294 | "url": "https://github.com/sponsors/isaacs" 295 | } 296 | }, 297 | "node_modules/help-me": { 298 | "version": "3.0.0", 299 | "resolved": "https://registry.npmjs.org/help-me/-/help-me-3.0.0.tgz", 300 | "integrity": "sha512-hx73jClhyk910sidBB7ERlnhMlFsJJIBqSVMFDwPN8o2v9nmp5KgLq1Xz1Bf1fCMMZ6mPrX159iG0VLy/fPMtQ==", 301 | "dependencies": { 302 | "glob": "^7.1.6", 303 | "readable-stream": "^3.6.0" 304 | } 305 | }, 306 | "node_modules/ieee754": { 307 | "version": "1.2.1", 308 | "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", 309 | "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", 310 | "funding": [ 311 | { 312 | "type": "github", 313 | "url": "https://github.com/sponsors/feross" 314 | }, 315 | { 316 | "type": "patreon", 317 | "url": "https://www.patreon.com/feross" 318 | }, 319 | { 320 | "type": "consulting", 321 | "url": "https://feross.org/support" 322 | } 323 | ] 324 | }, 325 | "node_modules/inflight": { 326 | "version": "1.0.6", 327 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 328 | "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", 329 | "dependencies": { 330 | "once": "^1.3.0", 331 | "wrappy": "1" 332 | } 333 | }, 334 | "node_modules/inherits": { 335 | "version": "2.0.4", 336 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 337 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 338 | }, 339 | "node_modules/js-sdsl": { 340 | "version": "4.1.4", 341 | "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.4.tgz", 342 | "integrity": "sha512-Y2/yD55y5jteOAmY50JbUZYwk3CP3wnLPEZnlR1w9oKhITrBEtAxwuWKebFf8hMrPMgbYwFoWK/lH2sBkErELw==" 343 | }, 344 | "node_modules/leven": { 345 | "version": "2.1.0", 346 | "resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz", 347 | "integrity": "sha512-nvVPLpIHUxCUoRLrFqTgSxXJ614d8AgQoWl7zPe/2VadE8+1dpU3LBhowRuBAcuwruWtOdD8oYC9jDNJjXDPyA==", 348 | "engines": { 349 | "node": ">=0.10.0" 350 | } 351 | }, 352 | "node_modules/lru-cache": { 353 | "version": "6.0.0", 354 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", 355 | "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", 356 | "dependencies": { 357 | "yallist": "^4.0.0" 358 | }, 359 | "engines": { 360 | "node": ">=10" 361 | } 362 | }, 363 | "node_modules/make-error": { 364 | "version": "1.3.6", 365 | "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", 366 | "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", 367 | "dev": true 368 | }, 369 | "node_modules/minimatch": { 370 | "version": "3.1.2", 371 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", 372 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", 373 | "dependencies": { 374 | "brace-expansion": "^1.1.7" 375 | }, 376 | "engines": { 377 | "node": "*" 378 | } 379 | }, 380 | "node_modules/minimist": { 381 | "version": "1.2.7", 382 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", 383 | "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", 384 | "funding": { 385 | "url": "https://github.com/sponsors/ljharb" 386 | } 387 | }, 388 | "node_modules/mqtt": { 389 | "version": "4.3.7", 390 | "resolved": "https://registry.npmjs.org/mqtt/-/mqtt-4.3.7.tgz", 391 | "integrity": "sha512-ew3qwG/TJRorTz47eW46vZ5oBw5MEYbQZVaEji44j5lAUSQSqIEoul7Kua/BatBW0H0kKQcC9kwUHa1qzaWHSw==", 392 | "dependencies": { 393 | "commist": "^1.0.0", 394 | "concat-stream": "^2.0.0", 395 | "debug": "^4.1.1", 396 | "duplexify": "^4.1.1", 397 | "help-me": "^3.0.0", 398 | "inherits": "^2.0.3", 399 | "lru-cache": "^6.0.0", 400 | "minimist": "^1.2.5", 401 | "mqtt-packet": "^6.8.0", 402 | "number-allocator": "^1.0.9", 403 | "pump": "^3.0.0", 404 | "readable-stream": "^3.6.0", 405 | "reinterval": "^1.1.0", 406 | "rfdc": "^1.3.0", 407 | "split2": "^3.1.0", 408 | "ws": "^7.5.5", 409 | "xtend": "^4.0.2" 410 | }, 411 | "bin": { 412 | "mqtt": "bin/mqtt.js", 413 | "mqtt_pub": "bin/pub.js", 414 | "mqtt_sub": "bin/sub.js" 415 | }, 416 | "engines": { 417 | "node": ">=10.0.0" 418 | } 419 | }, 420 | "node_modules/mqtt-packet": { 421 | "version": "6.10.0", 422 | "resolved": "https://registry.npmjs.org/mqtt-packet/-/mqtt-packet-6.10.0.tgz", 423 | "integrity": "sha512-ja8+mFKIHdB1Tpl6vac+sktqy3gA8t9Mduom1BA75cI+R9AHnZOiaBQwpGiWnaVJLDGRdNhQmFaAqd7tkKSMGA==", 424 | "dependencies": { 425 | "bl": "^4.0.2", 426 | "debug": "^4.1.1", 427 | "process-nextick-args": "^2.0.1" 428 | } 429 | }, 430 | "node_modules/ms": { 431 | "version": "2.1.2", 432 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 433 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" 434 | }, 435 | "node_modules/number-allocator": { 436 | "version": "1.0.12", 437 | "resolved": "https://registry.npmjs.org/number-allocator/-/number-allocator-1.0.12.tgz", 438 | "integrity": "sha512-sGB0qoQGmKimery9JubBQ9pQUr1V/LixJAk3Ygp7obZf6mpSXime8d7XHEobbIimkdZpgjkNlLt6G7LPEWFYWg==", 439 | "dependencies": { 440 | "debug": "^4.3.1", 441 | "js-sdsl": "4.1.4" 442 | } 443 | }, 444 | "node_modules/once": { 445 | "version": "1.4.0", 446 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 447 | "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", 448 | "dependencies": { 449 | "wrappy": "1" 450 | } 451 | }, 452 | "node_modules/path-is-absolute": { 453 | "version": "1.0.1", 454 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 455 | "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", 456 | "engines": { 457 | "node": ">=0.10.0" 458 | } 459 | }, 460 | "node_modules/process-nextick-args": { 461 | "version": "2.0.1", 462 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", 463 | "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" 464 | }, 465 | "node_modules/pump": { 466 | "version": "3.0.0", 467 | "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", 468 | "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", 469 | "dependencies": { 470 | "end-of-stream": "^1.1.0", 471 | "once": "^1.3.1" 472 | } 473 | }, 474 | "node_modules/readable-stream": { 475 | "version": "3.6.0", 476 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", 477 | "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", 478 | "dependencies": { 479 | "inherits": "^2.0.3", 480 | "string_decoder": "^1.1.1", 481 | "util-deprecate": "^1.0.1" 482 | }, 483 | "engines": { 484 | "node": ">= 6" 485 | } 486 | }, 487 | "node_modules/reinterval": { 488 | "version": "1.1.0", 489 | "resolved": "https://registry.npmjs.org/reinterval/-/reinterval-1.1.0.tgz", 490 | "integrity": "sha512-QIRet3SYrGp0HUHO88jVskiG6seqUGC5iAG7AwI/BV4ypGcuqk9Du6YQBUOUqm9c8pw1eyLoIaONifRua1lsEQ==" 491 | }, 492 | "node_modules/rfdc": { 493 | "version": "1.3.0", 494 | "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", 495 | "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==" 496 | }, 497 | "node_modules/safe-buffer": { 498 | "version": "5.2.1", 499 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 500 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 501 | "funding": [ 502 | { 503 | "type": "github", 504 | "url": "https://github.com/sponsors/feross" 505 | }, 506 | { 507 | "type": "patreon", 508 | "url": "https://www.patreon.com/feross" 509 | }, 510 | { 511 | "type": "consulting", 512 | "url": "https://feross.org/support" 513 | } 514 | ] 515 | }, 516 | "node_modules/split2": { 517 | "version": "3.2.2", 518 | "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", 519 | "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", 520 | "dependencies": { 521 | "readable-stream": "^3.0.0" 522 | } 523 | }, 524 | "node_modules/stream-shift": { 525 | "version": "1.0.1", 526 | "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", 527 | "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==" 528 | }, 529 | "node_modules/string_decoder": { 530 | "version": "1.3.0", 531 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", 532 | "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", 533 | "dependencies": { 534 | "safe-buffer": "~5.2.0" 535 | } 536 | }, 537 | "node_modules/ts-node": { 538 | "version": "10.9.1", 539 | "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", 540 | "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", 541 | "dev": true, 542 | "dependencies": { 543 | "@cspotcode/source-map-support": "^0.8.0", 544 | "@tsconfig/node10": "^1.0.7", 545 | "@tsconfig/node12": "^1.0.7", 546 | "@tsconfig/node14": "^1.0.0", 547 | "@tsconfig/node16": "^1.0.2", 548 | "acorn": "^8.4.1", 549 | "acorn-walk": "^8.1.1", 550 | "arg": "^4.1.0", 551 | "create-require": "^1.1.0", 552 | "diff": "^4.0.1", 553 | "make-error": "^1.1.1", 554 | "v8-compile-cache-lib": "^3.0.1", 555 | "yn": "3.1.1" 556 | }, 557 | "bin": { 558 | "ts-node": "dist/bin.js", 559 | "ts-node-cwd": "dist/bin-cwd.js", 560 | "ts-node-esm": "dist/bin-esm.js", 561 | "ts-node-script": "dist/bin-script.js", 562 | "ts-node-transpile-only": "dist/bin-transpile.js", 563 | "ts-script": "dist/bin-script-deprecated.js" 564 | }, 565 | "peerDependencies": { 566 | "@swc/core": ">=1.2.50", 567 | "@swc/wasm": ">=1.2.50", 568 | "@types/node": "*", 569 | "typescript": ">=2.7" 570 | }, 571 | "peerDependenciesMeta": { 572 | "@swc/core": { 573 | "optional": true 574 | }, 575 | "@swc/wasm": { 576 | "optional": true 577 | } 578 | } 579 | }, 580 | "node_modules/typedarray": { 581 | "version": "0.0.6", 582 | "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", 583 | "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" 584 | }, 585 | "node_modules/typescript": { 586 | "version": "4.9.3", 587 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.3.tgz", 588 | "integrity": "sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==", 589 | "dev": true, 590 | "bin": { 591 | "tsc": "bin/tsc", 592 | "tsserver": "bin/tsserver" 593 | }, 594 | "engines": { 595 | "node": ">=4.2.0" 596 | } 597 | }, 598 | "node_modules/util-deprecate": { 599 | "version": "1.0.2", 600 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 601 | "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" 602 | }, 603 | "node_modules/v8-compile-cache-lib": { 604 | "version": "3.0.1", 605 | "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", 606 | "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", 607 | "dev": true 608 | }, 609 | "node_modules/wrappy": { 610 | "version": "1.0.2", 611 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 612 | "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" 613 | }, 614 | "node_modules/ws": { 615 | "version": "7.5.9", 616 | "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", 617 | "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", 618 | "engines": { 619 | "node": ">=8.3.0" 620 | }, 621 | "peerDependencies": { 622 | "bufferutil": "^4.0.1", 623 | "utf-8-validate": "^5.0.2" 624 | }, 625 | "peerDependenciesMeta": { 626 | "bufferutil": { 627 | "optional": true 628 | }, 629 | "utf-8-validate": { 630 | "optional": true 631 | } 632 | } 633 | }, 634 | "node_modules/xtend": { 635 | "version": "4.0.2", 636 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", 637 | "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", 638 | "engines": { 639 | "node": ">=0.4" 640 | } 641 | }, 642 | "node_modules/yallist": { 643 | "version": "4.0.0", 644 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", 645 | "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" 646 | }, 647 | "node_modules/yn": { 648 | "version": "3.1.1", 649 | "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", 650 | "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", 651 | "dev": true, 652 | "engines": { 653 | "node": ">=6" 654 | } 655 | } 656 | }, 657 | "dependencies": { 658 | "@cspotcode/source-map-support": { 659 | "version": "0.8.1", 660 | "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", 661 | "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", 662 | "dev": true, 663 | "requires": { 664 | "@jridgewell/trace-mapping": "0.3.9" 665 | } 666 | }, 667 | "@jridgewell/resolve-uri": { 668 | "version": "3.1.0", 669 | "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", 670 | "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", 671 | "dev": true 672 | }, 673 | "@jridgewell/sourcemap-codec": { 674 | "version": "1.4.14", 675 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", 676 | "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", 677 | "dev": true 678 | }, 679 | "@jridgewell/trace-mapping": { 680 | "version": "0.3.9", 681 | "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", 682 | "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", 683 | "dev": true, 684 | "requires": { 685 | "@jridgewell/resolve-uri": "^3.0.3", 686 | "@jridgewell/sourcemap-codec": "^1.4.10" 687 | } 688 | }, 689 | "@tsconfig/node10": { 690 | "version": "1.0.9", 691 | "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", 692 | "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", 693 | "dev": true 694 | }, 695 | "@tsconfig/node12": { 696 | "version": "1.0.11", 697 | "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", 698 | "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", 699 | "dev": true 700 | }, 701 | "@tsconfig/node14": { 702 | "version": "1.0.3", 703 | "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", 704 | "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", 705 | "dev": true 706 | }, 707 | "@tsconfig/node16": { 708 | "version": "1.0.3", 709 | "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", 710 | "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", 711 | "dev": true 712 | }, 713 | "@types/node": { 714 | "version": "18.11.9", 715 | "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.9.tgz", 716 | "integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==", 717 | "dev": true 718 | }, 719 | "@types/ws": { 720 | "version": "8.5.3", 721 | "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz", 722 | "integrity": "sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==", 723 | "dev": true, 724 | "requires": { 725 | "@types/node": "*" 726 | } 727 | }, 728 | "acorn": { 729 | "version": "8.8.1", 730 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", 731 | "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", 732 | "dev": true 733 | }, 734 | "acorn-walk": { 735 | "version": "8.2.0", 736 | "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", 737 | "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", 738 | "dev": true 739 | }, 740 | "arg": { 741 | "version": "4.1.3", 742 | "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", 743 | "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", 744 | "dev": true 745 | }, 746 | "balanced-match": { 747 | "version": "1.0.2", 748 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 749 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" 750 | }, 751 | "base64-js": { 752 | "version": "1.5.1", 753 | "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", 754 | "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" 755 | }, 756 | "bl": { 757 | "version": "4.1.0", 758 | "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", 759 | "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", 760 | "requires": { 761 | "buffer": "^5.5.0", 762 | "inherits": "^2.0.4", 763 | "readable-stream": "^3.4.0" 764 | } 765 | }, 766 | "brace-expansion": { 767 | "version": "1.1.11", 768 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 769 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 770 | "requires": { 771 | "balanced-match": "^1.0.0", 772 | "concat-map": "0.0.1" 773 | } 774 | }, 775 | "buffer": { 776 | "version": "5.7.1", 777 | "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", 778 | "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", 779 | "requires": { 780 | "base64-js": "^1.3.1", 781 | "ieee754": "^1.1.13" 782 | } 783 | }, 784 | "buffer-from": { 785 | "version": "1.1.2", 786 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", 787 | "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" 788 | }, 789 | "commist": { 790 | "version": "1.1.0", 791 | "resolved": "https://registry.npmjs.org/commist/-/commist-1.1.0.tgz", 792 | "integrity": "sha512-rraC8NXWOEjhADbZe9QBNzLAN5Q3fsTPQtBV+fEVj6xKIgDgNiEVE6ZNfHpZOqfQ21YUzfVNUXLOEZquYvQPPg==", 793 | "requires": { 794 | "leven": "^2.1.0", 795 | "minimist": "^1.1.0" 796 | } 797 | }, 798 | "concat-map": { 799 | "version": "0.0.1", 800 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 801 | "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" 802 | }, 803 | "concat-stream": { 804 | "version": "2.0.0", 805 | "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", 806 | "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", 807 | "requires": { 808 | "buffer-from": "^1.0.0", 809 | "inherits": "^2.0.3", 810 | "readable-stream": "^3.0.2", 811 | "typedarray": "^0.0.6" 812 | } 813 | }, 814 | "create-require": { 815 | "version": "1.1.1", 816 | "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", 817 | "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", 818 | "dev": true 819 | }, 820 | "debug": { 821 | "version": "4.3.4", 822 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", 823 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", 824 | "requires": { 825 | "ms": "2.1.2" 826 | } 827 | }, 828 | "diff": { 829 | "version": "4.0.2", 830 | "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", 831 | "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", 832 | "dev": true 833 | }, 834 | "duplexify": { 835 | "version": "4.1.2", 836 | "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.2.tgz", 837 | "integrity": "sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw==", 838 | "requires": { 839 | "end-of-stream": "^1.4.1", 840 | "inherits": "^2.0.3", 841 | "readable-stream": "^3.1.1", 842 | "stream-shift": "^1.0.0" 843 | } 844 | }, 845 | "end-of-stream": { 846 | "version": "1.4.4", 847 | "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", 848 | "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", 849 | "requires": { 850 | "once": "^1.4.0" 851 | } 852 | }, 853 | "fs.realpath": { 854 | "version": "1.0.0", 855 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 856 | "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" 857 | }, 858 | "glob": { 859 | "version": "7.2.3", 860 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", 861 | "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", 862 | "requires": { 863 | "fs.realpath": "^1.0.0", 864 | "inflight": "^1.0.4", 865 | "inherits": "2", 866 | "minimatch": "^3.1.1", 867 | "once": "^1.3.0", 868 | "path-is-absolute": "^1.0.0" 869 | } 870 | }, 871 | "help-me": { 872 | "version": "3.0.0", 873 | "resolved": "https://registry.npmjs.org/help-me/-/help-me-3.0.0.tgz", 874 | "integrity": "sha512-hx73jClhyk910sidBB7ERlnhMlFsJJIBqSVMFDwPN8o2v9nmp5KgLq1Xz1Bf1fCMMZ6mPrX159iG0VLy/fPMtQ==", 875 | "requires": { 876 | "glob": "^7.1.6", 877 | "readable-stream": "^3.6.0" 878 | } 879 | }, 880 | "ieee754": { 881 | "version": "1.2.1", 882 | "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", 883 | "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" 884 | }, 885 | "inflight": { 886 | "version": "1.0.6", 887 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 888 | "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", 889 | "requires": { 890 | "once": "^1.3.0", 891 | "wrappy": "1" 892 | } 893 | }, 894 | "inherits": { 895 | "version": "2.0.4", 896 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 897 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 898 | }, 899 | "js-sdsl": { 900 | "version": "4.1.4", 901 | "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.4.tgz", 902 | "integrity": "sha512-Y2/yD55y5jteOAmY50JbUZYwk3CP3wnLPEZnlR1w9oKhITrBEtAxwuWKebFf8hMrPMgbYwFoWK/lH2sBkErELw==" 903 | }, 904 | "leven": { 905 | "version": "2.1.0", 906 | "resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz", 907 | "integrity": "sha512-nvVPLpIHUxCUoRLrFqTgSxXJ614d8AgQoWl7zPe/2VadE8+1dpU3LBhowRuBAcuwruWtOdD8oYC9jDNJjXDPyA==" 908 | }, 909 | "lru-cache": { 910 | "version": "6.0.0", 911 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", 912 | "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", 913 | "requires": { 914 | "yallist": "^4.0.0" 915 | } 916 | }, 917 | "make-error": { 918 | "version": "1.3.6", 919 | "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", 920 | "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", 921 | "dev": true 922 | }, 923 | "minimatch": { 924 | "version": "3.1.2", 925 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", 926 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", 927 | "requires": { 928 | "brace-expansion": "^1.1.7" 929 | } 930 | }, 931 | "minimist": { 932 | "version": "1.2.7", 933 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", 934 | "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==" 935 | }, 936 | "mqtt": { 937 | "version": "4.3.7", 938 | "resolved": "https://registry.npmjs.org/mqtt/-/mqtt-4.3.7.tgz", 939 | "integrity": "sha512-ew3qwG/TJRorTz47eW46vZ5oBw5MEYbQZVaEji44j5lAUSQSqIEoul7Kua/BatBW0H0kKQcC9kwUHa1qzaWHSw==", 940 | "requires": { 941 | "commist": "^1.0.0", 942 | "concat-stream": "^2.0.0", 943 | "debug": "^4.1.1", 944 | "duplexify": "^4.1.1", 945 | "help-me": "^3.0.0", 946 | "inherits": "^2.0.3", 947 | "lru-cache": "^6.0.0", 948 | "minimist": "^1.2.5", 949 | "mqtt-packet": "^6.8.0", 950 | "number-allocator": "^1.0.9", 951 | "pump": "^3.0.0", 952 | "readable-stream": "^3.6.0", 953 | "reinterval": "^1.1.0", 954 | "rfdc": "^1.3.0", 955 | "split2": "^3.1.0", 956 | "ws": "^7.5.5", 957 | "xtend": "^4.0.2" 958 | } 959 | }, 960 | "mqtt-packet": { 961 | "version": "6.10.0", 962 | "resolved": "https://registry.npmjs.org/mqtt-packet/-/mqtt-packet-6.10.0.tgz", 963 | "integrity": "sha512-ja8+mFKIHdB1Tpl6vac+sktqy3gA8t9Mduom1BA75cI+R9AHnZOiaBQwpGiWnaVJLDGRdNhQmFaAqd7tkKSMGA==", 964 | "requires": { 965 | "bl": "^4.0.2", 966 | "debug": "^4.1.1", 967 | "process-nextick-args": "^2.0.1" 968 | } 969 | }, 970 | "ms": { 971 | "version": "2.1.2", 972 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 973 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" 974 | }, 975 | "number-allocator": { 976 | "version": "1.0.12", 977 | "resolved": "https://registry.npmjs.org/number-allocator/-/number-allocator-1.0.12.tgz", 978 | "integrity": "sha512-sGB0qoQGmKimery9JubBQ9pQUr1V/LixJAk3Ygp7obZf6mpSXime8d7XHEobbIimkdZpgjkNlLt6G7LPEWFYWg==", 979 | "requires": { 980 | "debug": "^4.3.1", 981 | "js-sdsl": "4.1.4" 982 | } 983 | }, 984 | "once": { 985 | "version": "1.4.0", 986 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 987 | "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", 988 | "requires": { 989 | "wrappy": "1" 990 | } 991 | }, 992 | "path-is-absolute": { 993 | "version": "1.0.1", 994 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 995 | "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" 996 | }, 997 | "process-nextick-args": { 998 | "version": "2.0.1", 999 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", 1000 | "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" 1001 | }, 1002 | "pump": { 1003 | "version": "3.0.0", 1004 | "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", 1005 | "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", 1006 | "requires": { 1007 | "end-of-stream": "^1.1.0", 1008 | "once": "^1.3.1" 1009 | } 1010 | }, 1011 | "readable-stream": { 1012 | "version": "3.6.0", 1013 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", 1014 | "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", 1015 | "requires": { 1016 | "inherits": "^2.0.3", 1017 | "string_decoder": "^1.1.1", 1018 | "util-deprecate": "^1.0.1" 1019 | } 1020 | }, 1021 | "reinterval": { 1022 | "version": "1.1.0", 1023 | "resolved": "https://registry.npmjs.org/reinterval/-/reinterval-1.1.0.tgz", 1024 | "integrity": "sha512-QIRet3SYrGp0HUHO88jVskiG6seqUGC5iAG7AwI/BV4ypGcuqk9Du6YQBUOUqm9c8pw1eyLoIaONifRua1lsEQ==" 1025 | }, 1026 | "rfdc": { 1027 | "version": "1.3.0", 1028 | "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", 1029 | "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==" 1030 | }, 1031 | "safe-buffer": { 1032 | "version": "5.2.1", 1033 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 1034 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" 1035 | }, 1036 | "split2": { 1037 | "version": "3.2.2", 1038 | "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", 1039 | "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", 1040 | "requires": { 1041 | "readable-stream": "^3.0.0" 1042 | } 1043 | }, 1044 | "stream-shift": { 1045 | "version": "1.0.1", 1046 | "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", 1047 | "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==" 1048 | }, 1049 | "string_decoder": { 1050 | "version": "1.3.0", 1051 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", 1052 | "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", 1053 | "requires": { 1054 | "safe-buffer": "~5.2.0" 1055 | } 1056 | }, 1057 | "ts-node": { 1058 | "version": "10.9.1", 1059 | "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", 1060 | "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", 1061 | "dev": true, 1062 | "requires": { 1063 | "@cspotcode/source-map-support": "^0.8.0", 1064 | "@tsconfig/node10": "^1.0.7", 1065 | "@tsconfig/node12": "^1.0.7", 1066 | "@tsconfig/node14": "^1.0.0", 1067 | "@tsconfig/node16": "^1.0.2", 1068 | "acorn": "^8.4.1", 1069 | "acorn-walk": "^8.1.1", 1070 | "arg": "^4.1.0", 1071 | "create-require": "^1.1.0", 1072 | "diff": "^4.0.1", 1073 | "make-error": "^1.1.1", 1074 | "v8-compile-cache-lib": "^3.0.1", 1075 | "yn": "3.1.1" 1076 | } 1077 | }, 1078 | "typedarray": { 1079 | "version": "0.0.6", 1080 | "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", 1081 | "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" 1082 | }, 1083 | "typescript": { 1084 | "version": "4.9.3", 1085 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.3.tgz", 1086 | "integrity": "sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==", 1087 | "dev": true 1088 | }, 1089 | "util-deprecate": { 1090 | "version": "1.0.2", 1091 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 1092 | "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" 1093 | }, 1094 | "v8-compile-cache-lib": { 1095 | "version": "3.0.1", 1096 | "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", 1097 | "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", 1098 | "dev": true 1099 | }, 1100 | "wrappy": { 1101 | "version": "1.0.2", 1102 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1103 | "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" 1104 | }, 1105 | "ws": { 1106 | "version": "7.5.9", 1107 | "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", 1108 | "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", 1109 | "requires": {} 1110 | }, 1111 | "xtend": { 1112 | "version": "4.0.2", 1113 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", 1114 | "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" 1115 | }, 1116 | "yallist": { 1117 | "version": "4.0.0", 1118 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", 1119 | "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" 1120 | }, 1121 | "yn": { 1122 | "version": "3.1.1", 1123 | "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", 1124 | "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", 1125 | "dev": true 1126 | } 1127 | } 1128 | } 1129 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@droneblocks/go1-js", 3 | "version": "0.1.5", 4 | "description": "", 5 | "main": "./dist/go1.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "build": "tsc", 9 | "start": "ts-node ./examples/move-forward.ts" 10 | }, 11 | "files": [ 12 | "dist" 13 | ], 14 | "keywords": [ 15 | "unitree", 16 | "go1" 17 | ], 18 | "author": "Dennis Baldwin, DroneBlocks", 19 | "license": "MIT", 20 | "dependencies": { 21 | "mqtt": "^4.3.7" 22 | }, 23 | "devDependencies": { 24 | "@types/node": "^18.11.9", 25 | "@types/ws": "^8.5.3", 26 | "ts-node": "^10.9.1", 27 | "typescript": "^4.9.3" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/go1.ts: -------------------------------------------------------------------------------- 1 | import { EventEmitter } from "events"; 2 | import { Go1MQTT } from "./mqtt/go1-mqtt"; 3 | import { Go1State, getGo1StateCopy } from "./mqtt/go1-state"; 4 | import { IClientOptions } from "mqtt"; 5 | 6 | export enum Go1Mode { 7 | dance1 = "dance1", 8 | dance2 = "dance2", 9 | straightHand1 = "straightHand1", 10 | damping = "damping", 11 | standUp = "standUp", 12 | standDown = "standDown", 13 | recoverStand = "recoverStand", 14 | stand = "stand", 15 | walk = "walk", 16 | run = "run", 17 | climb = "climb", 18 | } 19 | 20 | export class Go1 extends EventEmitter { 21 | mqtt: Go1MQTT; 22 | go1State: Go1State; 23 | 24 | constructor(iClientOptions?: IClientOptions) { 25 | super(); 26 | this.mqtt = new Go1MQTT(this, iClientOptions); 27 | this.go1State = getGo1StateCopy(); 28 | } 29 | 30 | init = () => { 31 | this.mqtt.connect(); 32 | this.mqtt.subscribe(); 33 | }; 34 | /** 35 | * 36 | * @param state 37 | */ 38 | publishState = (state: Go1State) => { 39 | this.emit("go1StateChange", state); 40 | }; 41 | 42 | /** 43 | * 44 | * @param connected 45 | */ 46 | publishConnectionStatus = (connected: boolean) => { 47 | this.emit("go1ConnectionStatus", connected); 48 | }; 49 | 50 | /** 51 | * Move forward based on speed and time 52 | * 53 | * @param speed - A value from 0 to 1 54 | * @param lengthOfTime - Length of time for movement in milliseconds 55 | */ 56 | goForward = async (speed: number, lengthOfTime: number) => { 57 | this.mqtt.updateSpeed(0, 0, 0, speed); 58 | await this.mqtt.sendMovementCommand(lengthOfTime); 59 | }; 60 | 61 | /** 62 | * Move backward based on speed and time 63 | * 64 | * @param speed - A value from 0 to 1 65 | * @param lengthOfTime - Length of time for movement in milliseconds 66 | */ 67 | goBackward = async (speed: number, lengthOfTime: number) => { 68 | this.mqtt.updateSpeed(0, 0, 0, speed * -1.0); 69 | await this.mqtt.sendMovementCommand(lengthOfTime); 70 | }; 71 | 72 | /** 73 | * Move left based on speed and time 74 | * 75 | * @param speed - A value from 0 to 1 76 | * @param lengthOfTime - Length of time for movement in milliseconds 77 | */ 78 | goLeft = async (speed: number, lengthOfTime: number) => { 79 | this.mqtt.updateSpeed(speed * -1, 0, 0, 0); 80 | await this.mqtt.sendMovementCommand(lengthOfTime); 81 | }; 82 | 83 | /** 84 | * Move right based on speed and time 85 | * 86 | * @param speed - A value from 0 to 1 87 | * @param lengthOfTime - Length of time for movement in milliseconds 88 | */ 89 | goRight = async (speed: number, lengthOfTime: number) => { 90 | this.mqtt.updateSpeed(speed, 0, 0, 0); 91 | await this.mqtt.sendMovementCommand(lengthOfTime); 92 | }; 93 | 94 | /** 95 | * 96 | * Go left/right, turn left/right, and go forward/backward based on speed and time 97 | * 98 | * @param leftRightSpeed - A value from -1 to 1 99 | * @param turnLeftRightSpeed - A value from -1 to 1 100 | * @param backwardForwardSpeed - A value from -1 to 1 101 | * @param lengthOfTime - Length of time for movement in milliseconds 102 | */ 103 | go = async ( 104 | leftRightSpeed: number, 105 | turnLeftRightSpeed: number, 106 | backwardForwardSpeed: number, 107 | lengthOfTime: number 108 | ) => { 109 | this.mqtt.updateSpeed( 110 | leftRightSpeed, 111 | turnLeftRightSpeed, 112 | 0, 113 | backwardForwardSpeed 114 | ); 115 | await this.mqtt.sendMovementCommand(lengthOfTime); 116 | }; 117 | 118 | /** 119 | * Rotate left based on speed and time 120 | * 121 | * @param speed - A value from 0 to 1 122 | * @param lengthOfTime - Length of time for movement in milliseconds 123 | */ 124 | turnLeft = async (speed: number, lengthOfTime: number) => { 125 | this.mqtt.updateSpeed(0, speed * -1, 0, 0); 126 | await this.mqtt.sendMovementCommand(lengthOfTime); 127 | }; 128 | 129 | /** 130 | * Rotate right based on speed and time 131 | * 132 | * @param speed - A value from 0 to 1 133 | * @param lengthOfTime - Length of time for movement in milliseconds 134 | */ 135 | turnRight = async (speed: number, lengthOfTime: number) => { 136 | this.mqtt.updateSpeed(0, speed, 0, 0); 137 | await this.mqtt.sendMovementCommand(lengthOfTime); 138 | }; 139 | 140 | /** 141 | * Raw pose method for accessing all of the axes together. Requires stand mode to be set first. 142 | * 143 | * @param leanLeftRightAmount - A value from -1 to 1 144 | * @param twistLeftRightAmount - A value from -1 to 1 145 | * @param lookUpDownAmount - A value from -1 to 1 (only for stand mode) 146 | * @param extendSquatAmount - A value from -1 to 1 147 | * @param lengthOfTime - Length of time for movement in milliseconds 148 | */ 149 | pose = async ( 150 | leanLeftRightAmount: number, 151 | twistLeftRightAmount: number, 152 | lookUpDownAmount: number, 153 | extendSquatAmount: number, 154 | lengthOfTime: number 155 | ) => { 156 | this.mqtt.updateSpeed( 157 | leanLeftRightAmount, 158 | twistLeftRightAmount, 159 | lookUpDownAmount, 160 | extendSquatAmount 161 | ); 162 | await this.mqtt.sendMovementCommand(lengthOfTime); 163 | }; 164 | 165 | /** 166 | * Extend up - requires setMode(Go1Mode.stand) to be set 167 | * 168 | * @param speed - A value from 0 to 1 169 | * @param lengthOfTime - Length of time for movement in milliseconds 170 | */ 171 | extendUp = async (speed: number, lengthOfTime: number) => { 172 | this.mqtt.updateSpeed(0, 0, 0, speed); 173 | await this.mqtt.sendMovementCommand(lengthOfTime); 174 | }; 175 | 176 | /** 177 | * Squat up - requires setMode(Go1Mode.stand) to be set 178 | * 179 | * @param speed - A value from 0 to 1 180 | * @param lengthOfTime - Length of time for movement in milliseconds 181 | */ 182 | squatDown = async (speed: number, lengthOfTime: number) => { 183 | this.mqtt.updateSpeed(0, 0, 0, speed * -1); 184 | await this.mqtt.sendMovementCommand(lengthOfTime); 185 | }; 186 | 187 | /** 188 | * Leans body to the left - requires setMode(Go1Mode.stand) to be set 189 | * 190 | * @param speed - A value from 0 to 1 191 | * @param lengthOfTime - Length of time for movement in milliseconds 192 | */ 193 | leanLeft = async (speed: number, lengthOfTime: number) => { 194 | this.mqtt.updateSpeed(speed * -1, 0, 0, 0); 195 | await this.mqtt.sendMovementCommand(lengthOfTime); 196 | }; 197 | 198 | /** 199 | * Leans body to the right - requires setMode(Go1Mode.stand) to be set 200 | * 201 | * @param speed - A value from 0 to 1 202 | * @param lengthOfTime - Length of time for movement in milliseconds 203 | */ 204 | leanRight = async (speed: number, lengthOfTime: number) => { 205 | this.mqtt.updateSpeed(speed, 0, 0, 0); 206 | await this.mqtt.sendMovementCommand(lengthOfTime); 207 | }; 208 | 209 | /** 210 | * Twists body to the left - requires setMode(Go1Mode.stand) to be set 211 | * 212 | * @param speed - A value from 0 to 1 213 | * @param lengthOfTime - Length of time for movement in milliseconds 214 | */ 215 | twistLeft = async (speed: number, lengthOfTime: number) => { 216 | this.mqtt.updateSpeed(0, speed * -1, 0, 0); 217 | await this.mqtt.sendMovementCommand(lengthOfTime); 218 | }; 219 | 220 | /** 221 | * Twists body to the right - requires setMode(Go1Mode.stand) to be set 222 | * 223 | * @param speed - A value from 0 to 1 224 | * @param lengthOfTime - Length of time for movement in milliseconds 225 | */ 226 | twistRight = async (speed: number, lengthOfTime: number) => { 227 | this.mqtt.updateSpeed(0, speed, 0, 0); 228 | await this.mqtt.sendMovementCommand(lengthOfTime); 229 | }; 230 | 231 | /** 232 | * Leans body down - requires setMode(Go1Mode.stand) to be set 233 | * 234 | * @param speed - A value from 0 to 1 235 | * @param lengthOfTime - Length of time for movement in milliseconds 236 | */ 237 | lookDown = async (speed: number, lengthOfTime: number) => { 238 | this.mqtt.updateSpeed(0, 0, speed, 0); 239 | await this.mqtt.sendMovementCommand(lengthOfTime); 240 | }; 241 | 242 | /** 243 | * Leans body up - requires setMode(Go1Mode.stand) to be set 244 | * 245 | * @param speed - A value from 0 to 1 246 | * @param lengthOfTime - Length of time for movement in milliseconds 247 | */ 248 | lookUp = async (speed: number, lengthOfTime: number) => { 249 | this.mqtt.updateSpeed(0, 0, speed * -1, 0); 250 | await this.mqtt.sendMovementCommand(lengthOfTime); 251 | }; 252 | 253 | /** 254 | * Helper function to clear out previous queued movements 255 | */ 256 | resetBody = async () => { 257 | this.mqtt.updateSpeed(0, 0, 0, 0); 258 | await this.mqtt.sendMovementCommand(1000); 259 | }; 260 | 261 | /** 262 | * Wait for a period of time 263 | * 264 | * @param lengthOfTime - Length of time for wait in milliseconds 265 | */ 266 | wait = (lengthOfTime: number) => { 267 | return new Promise((resolve) => setTimeout(resolve, lengthOfTime)); 268 | }; 269 | 270 | /** 271 | * Change Go1's LED color 272 | * 273 | * @param r - A red value from 0 to 255 274 | * @param g - A green value from 0 to 255 275 | * @param b - A blue value from 0 to 255 276 | */ 277 | setLedColor = (r: number, g: number, b: number) => { 278 | this.mqtt.sendLEDCommand(r, g, b); 279 | }; 280 | 281 | /** 282 | * Set Go1's operation mode 283 | * 284 | * @param mode 285 | * Go1Mode.dance1 286 | * Go1Mode.dance2 287 | * Go1Mode.straightHand1 288 | * Go1Mode.damping 289 | * Go1Mode.standUp, 290 | * Go1Mode.standDown 291 | * Go1Mode.recoverStand 292 | * Go1Mode.stand 293 | * Go1Mode.walk 294 | * Go1Mode.run 295 | * Go1Mode.climb 296 | */ 297 | setMode = (mode: Go1Mode) => { 298 | this.mqtt.sendModeCommand(mode); 299 | }; 300 | } 301 | 302 | /** 303 | * stand 304 | * 0, 0, 0, 1 = stand tall (W) 305 | * 0, 0, 0, -1 = stand short (S) 306 | * 307 | * -1, 0, 0, 0 - tilt left (A) 308 | * 1, 0, 0, 0 - tilt right (D) 309 | * 310 | * 0, -1, 0, 0 - look left (left arrow) 311 | * 0, 1, 0, 0 - look right (right arrow) 312 | * 313 | * 0, 0, -1, 0 - look down (up arrow) 314 | * 0, 0, 1, 0 - look up (down arrow) 315 | */ 316 | -------------------------------------------------------------------------------- /src/mqtt/go1-mqtt.ts: -------------------------------------------------------------------------------- 1 | import { connect, MqttClient, IClientOptions } from "mqtt"; 2 | import { Go1State, getGo1StateCopy } from "./go1-state"; 3 | import { Go1, Go1Mode } from "../go1"; 4 | import messageHandler from "./message-handler"; 5 | 6 | export class Go1MQTT { 7 | go1: Go1; 8 | client: MqttClient | null; 9 | floats: Float32Array = new Float32Array(4); 10 | connected: boolean = false; 11 | movementTopic: string; 12 | ledTopic: string; 13 | modeTopic: string; 14 | publishFrequency: number; 15 | go1State: Go1State; 16 | iClientOptions: IClientOptions; 17 | 18 | readonly defaultIClientOptions: IClientOptions = { 19 | port: 1883, 20 | host: "192.168.12.1", 21 | clientId: Math.random().toString(16).substring(2, 8), 22 | keepalive: 5, 23 | protocol: "mqtt", 24 | }; 25 | 26 | constructor(go1: Go1, iClientOptions?: IClientOptions) { 27 | this.go1 = go1; 28 | this.iClientOptions = { ...this.defaultIClientOptions, ...iClientOptions }; 29 | this.client = null; 30 | this.floats[0] = 0; // walk left (neg) and right (pos) 31 | this.floats[1] = 0; // turn left (neg) and right (pos) 32 | this.floats[2] = 0; 33 | this.floats[3] = 0; // walk backward (neg) and forward (pos) 34 | this.movementTopic = "controller/stick"; 35 | this.ledTopic = "programming/code"; 36 | this.modeTopic = "controller/action"; 37 | this.publishFrequency = 100; // Send MQTT message every 100ms 38 | this.go1State = getGo1StateCopy(); 39 | } 40 | 41 | connect = () => { 42 | console.log("connecting"); 43 | this.client = connect(this.iClientOptions); 44 | 45 | this.client.on("connect", () => { 46 | console.log("connected"); 47 | this.connected = true; 48 | this.go1.publishConnectionStatus(true); 49 | }); 50 | 51 | this.client.on("close", () => { 52 | this.connected = false; 53 | }); 54 | 55 | this.client.on("disconnect", () => { 56 | console.log("disconnected"); 57 | this.go1.publishConnectionStatus(false); 58 | }); 59 | 60 | this.client.on("offline", () => { 61 | console.log("disconnected"); 62 | this.go1.publishConnectionStatus(false); 63 | }); 64 | 65 | // Handle messages that come from various topics 66 | this.client.on("message", (topic, message) => { 67 | this.go1.publishState(this.go1State); 68 | messageHandler(topic, message, this.go1State); 69 | }); 70 | }; 71 | 72 | // Subscribe to topics for updates 73 | subscribe = () => { 74 | this.client?.subscribe(["bms/state", "firmware/version"]); 75 | }; 76 | 77 | getState = (): Go1State => { 78 | return this.go1State; 79 | }; 80 | 81 | disconnect = () => { 82 | this.client?.end(); 83 | }; 84 | 85 | updateSpeed = ( 86 | leftRight: number, 87 | turnLeftRight: number, 88 | lookUpDown: number, // Only for stand mode 89 | backwardForward: number 90 | ) => { 91 | this.floats[0] = this.clamp(leftRight); 92 | this.floats[1] = this.clamp(turnLeftRight); 93 | this.floats[2] = this.clamp(lookUpDown); 94 | this.floats[3] = this.clamp(backwardForward); 95 | }; 96 | 97 | sendMovementCommand = async (lengthOfTime: number) => { 98 | let interval: ReturnType; 99 | 100 | let zero: Float32Array = new Float32Array(4); 101 | zero[0] = 0; 102 | zero[1] = 0; 103 | zero[2] = 0; 104 | zero[3] = 0; 105 | 106 | // Reset speed from the buffer for a few 107 | this.client?.publish( 108 | this.movementTopic, 109 | new Uint8Array(zero.buffer) as Buffer, 110 | { 111 | qos: 0, 112 | } 113 | ); 114 | 115 | interval = setInterval(() => { 116 | console.log(`sending command ${this.floats}`); 117 | this.client?.publish( 118 | this.movementTopic, 119 | new Uint8Array(this.floats.buffer) as Buffer, 120 | { 121 | qos: 0, 122 | } 123 | ); 124 | }, this.publishFrequency); 125 | 126 | // Stop sending after lengthOfTime 127 | return new Promise((resolve) => { 128 | setTimeout(() => { 129 | resolve(); 130 | clearInterval(interval); 131 | }, lengthOfTime); 132 | }); 133 | }; 134 | 135 | sendLEDCommand = (r: number, g: number, b: number) => { 136 | this.client?.publish( 137 | this.ledTopic, 138 | `child_conn.send('change_light(${r},${g},${b})')`, 139 | { 140 | qos: 0, 141 | } 142 | ); 143 | }; 144 | 145 | sendModeCommand = (mode: Go1Mode) => { 146 | this.client?.publish(this.modeTopic, mode, { 147 | qos: 1, 148 | }); 149 | }; 150 | 151 | clamp = (speed: number) => { 152 | if (speed < -1.0) { 153 | return -1.0; 154 | } else if (speed > 1.0) { 155 | return 1.0; 156 | } else { 157 | return speed; 158 | } 159 | }; 160 | } 161 | -------------------------------------------------------------------------------- /src/mqtt/go1-state.ts: -------------------------------------------------------------------------------- 1 | export type AiMode = "MNFH" | "cam1" | "cam2" | "cam3" | "cam4" | "cam5"; 2 | 3 | export interface Go1State { 4 | mqttConnected: boolean; 5 | managerOn: boolean; 6 | controllerOn: boolean; 7 | bms: { 8 | version: string; 9 | status: number; 10 | soc: number; 11 | current: number; 12 | cycle: number; 13 | temps: number[]; 14 | voltage: number; 15 | cellVoltages: number[]; 16 | }; 17 | robot: { 18 | sn: { 19 | product: string; 20 | id: string; 21 | }; 22 | version: { 23 | hardware: string; 24 | software: string; 25 | }; 26 | temps: number[]; 27 | mode: number; 28 | gaitType: number; 29 | obstacles: number[]; 30 | state: string; 31 | distanceWarning: { 32 | front: number; 33 | back: number; 34 | left: number; 35 | right: number; 36 | }; 37 | }; 38 | } 39 | 40 | const data: Go1State = { 41 | mqttConnected: false, 42 | managerOn: false, 43 | controllerOn: false, 44 | bms: { 45 | version: "unknown", 46 | status: 0, 47 | soc: 0, 48 | current: 0, 49 | cycle: 0, 50 | temps: new Array(4).fill(0), 51 | voltage: 0, 52 | cellVoltages: new Array(10).fill(0), 53 | }, 54 | robot: { 55 | version: { 56 | hardware: "--", 57 | software: "--", 58 | }, 59 | sn: { 60 | product: "--", 61 | id: "--", 62 | }, 63 | temps: new Array(20).fill(0), 64 | mode: 0, 65 | gaitType: 0, 66 | obstacles: [255, 255, 255, 255], 67 | state: "invalid", 68 | distanceWarning: { 69 | front: 0, 70 | back: 0, 71 | left: 0, 72 | right: 0, 73 | }, 74 | }, 75 | }; 76 | 77 | const dataCopy = JSON.stringify(data); 78 | 79 | export const getGo1StateCopy = () => { 80 | return JSON.parse(dataCopy) as Go1State; 81 | }; 82 | -------------------------------------------------------------------------------- /src/mqtt/message-handler.ts: -------------------------------------------------------------------------------- 1 | import { Go1State } from "./go1-state"; 2 | import { SubTopic } from "./topics"; 3 | import bmsReceivers from "./receivers/bms-receiver"; 4 | import robotReceivers from "./receivers/robot-receiver"; 5 | 6 | type Receivers = { 7 | [key in SubTopic]: ( 8 | data: Go1State, 9 | message: Buffer, 10 | dataView: DataView 11 | ) => void; 12 | }; 13 | 14 | const messageReceivers: Receivers = { 15 | ...bmsReceivers, 16 | ...robotReceivers, 17 | }; 18 | 19 | export default function messageHandler( 20 | topic: string, 21 | message: Buffer, 22 | data: Go1State 23 | ) { 24 | const msgTopic = topic as SubTopic; 25 | const dataView = new DataView( 26 | message.buffer, 27 | message.byteOffset, 28 | message.byteLength 29 | ); 30 | const receiver = messageReceivers[msgTopic]; 31 | if (receiver) receiver(data, message, dataView); 32 | //else console.log(message); 33 | } 34 | -------------------------------------------------------------------------------- /src/mqtt/receivers/bms-receiver.ts: -------------------------------------------------------------------------------- 1 | import { Go1State } from "../go1-state"; 2 | import { BmsSubTopic } from "../topics"; 3 | 4 | type Receivers = { 5 | [key in BmsSubTopic]: ( 6 | data: Go1State, 7 | message: Buffer, 8 | dataView: DataView 9 | ) => void; 10 | }; 11 | 12 | const receivers: Receivers = { 13 | "bms/state": (data, message, dataView) => { 14 | const uint8s = new Uint8Array(message); 15 | //console.log(uint8s); 16 | data.bms.version = uint8s[0] + "." + uint8s[1]; 17 | data.bms.status = uint8s[2]; 18 | data.bms.soc = uint8s[3]; 19 | data.bms.current = dataView.getInt32(4, true); 20 | data.bms.cycle = dataView.getUint16(8, true); 21 | data.bms.temps = [uint8s[10], uint8s[11], uint8s[12], uint8s[13]]; 22 | for (let i = 0; i < 10; i++) { 23 | data.bms.cellVoltages[i] = dataView.getUint16(14 + i * 2, true); 24 | } 25 | data.bms.voltage = data.bms.cellVoltages.reduce((a, c) => a + c); 26 | }, 27 | }; 28 | 29 | export default receivers; 30 | -------------------------------------------------------------------------------- /src/mqtt/receivers/robot-receiver.ts: -------------------------------------------------------------------------------- 1 | import { Go1State } from "../go1-state"; 2 | import { FirmwareSubTopic } from "../topics"; 3 | 4 | type Receivers = { 5 | [key in FirmwareSubTopic]: ( 6 | data: Go1State, 7 | message: Buffer, 8 | dataView: DataView 9 | ) => void; 10 | }; 11 | 12 | function distanceToWarning(distance: number) { 13 | if (distance > 30) return 0; 14 | else if (distance < 10) return 1; 15 | else { 16 | return 0.2 + (0.8 * (30 - distance)) / 20; 17 | } 18 | } 19 | 20 | const receivers: Receivers = { 21 | "firmware/version": (data, message, dataView) => { 22 | //console.log(dataView); 23 | data.robot.temps = data.robot.temps.map((v, i) => dataView.getUint8(i + 8)); 24 | if (dataView.byteLength > 28) { 25 | data.robot.mode = dataView.getUint8(28); 26 | data.robot.gaitType = dataView.getUint8(29); 27 | data.robot.obstacles = data.robot.obstacles.map((v, i) => 28 | dataView.getUint8(i + 30) 29 | ); 30 | if (data.robot.mode === 2) { 31 | if (data.robot.gaitType === 2) data.robot.state = "run"; 32 | else if (data.robot.gaitType === 3) data.robot.state = "climb"; 33 | else if (data.robot.gaitType === 1) data.robot.state = "walk"; 34 | } 35 | 36 | data.robot.distanceWarning = { 37 | front: distanceToWarning(data.robot.obstacles[0]), 38 | back: distanceToWarning(data.robot.obstacles[3]), 39 | left: distanceToWarning(data.robot.obstacles[1]), 40 | right: distanceToWarning(data.robot.obstacles[2]), 41 | }; 42 | } 43 | if (dataView.byteLength >= 44) { 44 | let name = ""; 45 | switch (dataView.getUint8(0)) { 46 | case 1: 47 | name = "Laikago"; 48 | break; 49 | case 2: 50 | name = "Aliengo"; 51 | break; 52 | case 3: 53 | name = "A1"; 54 | break; 55 | case 4: 56 | name = "Go1"; 57 | break; 58 | case 5: 59 | name = "B1"; 60 | break; 61 | } 62 | let model = ""; 63 | switch (dataView.getUint8(1)) { 64 | case 1: 65 | model = "AIR"; 66 | break; 67 | case 2: 68 | model = "PRO"; 69 | break; 70 | case 3: 71 | model = "EDU"; 72 | break; 73 | case 4: 74 | model = "PC"; 75 | break; 76 | case 5: 77 | model = "XX"; 78 | break; 79 | } 80 | if (name != "") data.robot.sn.product = name + "_" + model; 81 | 82 | if (dataView.getUint8(2) < 255) 83 | data.robot.sn.id = 84 | dataView.getUint8(2) + 85 | "-" + 86 | dataView.getUint8(3) + 87 | "-" + 88 | dataView.getUint8(4) + 89 | "[" + 90 | dataView.getUint8(5) + 91 | "]"; 92 | if (dataView.getUint8(36) < 255) 93 | data.robot.version.hardware = 94 | dataView.getUint8(36) + 95 | "." + 96 | dataView.getUint8(37) + 97 | "." + 98 | dataView.getUint8(38); 99 | data.robot.version.software = 100 | dataView.getUint8(39) + 101 | "." + 102 | dataView.getUint8(40) + 103 | "." + 104 | dataView.getUint8(41); 105 | } 106 | }, 107 | }; 108 | 109 | export default receivers; 110 | -------------------------------------------------------------------------------- /src/mqtt/topics.ts: -------------------------------------------------------------------------------- 1 | export type BmsSubTopic = "bms/state"; 2 | export type FirmwareSubTopic = "firmware/version"; 3 | export type SubTopic = BmsSubTopic | FirmwareSubTopic; 4 | export type PubTopic = 5 | | "controller/action" 6 | | "controller/stick" 7 | | "programming/code"; 8 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2016", 4 | "module": "commonjs", 5 | "strict": true, 6 | "declaration": true, 7 | "rootDir": "./src", 8 | "outDir": "./dist", 9 | "types": ["node"] 10 | }, 11 | "exclude": ["tests", "dist", "node_modules", "examples"] 12 | } 13 | --------------------------------------------------------------------------------