├── .eslintignore ├── .eslintrc.json ├── .github └── workflows │ ├── codeql-analysis.yml │ └── nodejs.yml ├── .gitignore ├── .markdownlint.json ├── .vscode └── launch.json ├── CHANGELOG.md ├── LICENSE ├── README.md ├── dist ├── example.d.ts ├── example.js ├── example.js.map ├── index.d.ts ├── index.js ├── index.js.map ├── messages │ ├── ConnectionMessage.d.ts │ ├── ConnectionMessage.js │ ├── ConnectionMessage.js.map │ ├── OutgoingMessages.d.ts │ ├── OutgoingMessages.js │ ├── OutgoingMessages.js.map │ ├── SLGatewayDataMessage.d.ts │ ├── SLGatewayDataMessage.js │ ├── SLGatewayDataMessage.js.map │ ├── SLMessage.d.ts │ ├── SLMessage.js │ ├── SLMessage.js.map │ ├── config │ │ ├── CircuitMessage.d.ts │ │ ├── CircuitMessage.js │ │ ├── CircuitMessage.js.map │ │ ├── EquipmentConfig.d.ts │ │ ├── EquipmentConfig.js │ │ ├── EquipmentConfig.js.map │ │ ├── HeaterMessage.d.ts │ │ ├── HeaterMessage.js │ │ ├── HeaterMessage.js.map │ │ ├── ScheduleMessage.d.ts │ │ ├── ScheduleMessage.js │ │ └── ScheduleMessage.js.map │ └── state │ │ ├── ChemMessage.d.ts │ │ ├── ChemMessage.js │ │ ├── ChemMessage.js.map │ │ ├── ChlorMessage.d.ts │ │ ├── ChlorMessage.js │ │ ├── ChlorMessage.js.map │ │ ├── EquipmentState.d.ts │ │ ├── EquipmentState.js │ │ ├── EquipmentState.js.map │ │ ├── PumpMessage.d.ts │ │ ├── PumpMessage.js │ │ └── PumpMessage.js.map └── utils │ ├── PasswordEncoder.d.ts │ ├── PasswordEncoder.js │ └── PasswordEncoder.js.map ├── example.ts ├── index.ts ├── messages ├── ConnectionMessage.ts ├── OutgoingMessages.ts ├── SLGatewayDataMessage.ts ├── SLMessage.ts ├── config │ ├── CircuitMessage.ts │ ├── EquipmentConfig.ts │ ├── HeaterMessage.ts │ └── ScheduleMessage.ts └── state │ ├── ChemMessage.ts │ ├── ChlorMessage.ts │ ├── EquipmentState.ts │ └── PumpMessage.ts ├── package-lock.json ├── package.json ├── test ├── find.spec.js ├── password.spec.js ├── slmessage.spec.js └── unit.spec.js ├── tsconfig.json └── utils └── PasswordEncoder.ts /.eslintignore: -------------------------------------------------------------------------------- 1 | **/test/*.js 2 | **/dist/*.js 3 | **/*.d.ts 4 | test/ 5 | dist/ 6 | **/*.js -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "es2021": true, 4 | "node": true, 5 | "mocha": true 6 | }, 7 | "extends": [ 8 | "eslint:recommended", 9 | "plugin:@typescript-eslint/recommended" 10 | ], 11 | "parser": "@typescript-eslint/parser", 12 | "parserOptions": { 13 | "ecmaVersion": "latest", 14 | "sourceType": "module" 15 | }, 16 | "plugins": [ 17 | "@typescript-eslint" 18 | ], 19 | "rules": { 20 | "indent": [ 21 | "error", 22 | 2, 23 | { 24 | "SwitchCase": 1 25 | } 26 | ], 27 | "linebreak-style": "off", 28 | "quotes": [ 29 | "error", 30 | "single" 31 | ], 32 | "semi": [ 33 | "error", 34 | "always" 35 | ], 36 | "@typescript-eslint/no-explicit-any": "error" 37 | } 38 | } -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | name: "CodeQL" 7 | 8 | on: 9 | push: 10 | branches: [main] 11 | pull_request: 12 | # The branches below must be a subset of the branches above 13 | branches: [main] 14 | 15 | jobs: 16 | analyze: 17 | name: Analyze 18 | runs-on: ubuntu-latest 19 | 20 | strategy: 21 | fail-fast: false 22 | matrix: 23 | # Override automatic language detection by changing the below list 24 | # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python'] 25 | language: ['javascript'] 26 | # Learn more... 27 | # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection 28 | 29 | steps: 30 | - name: Checkout repository 31 | uses: actions/checkout@v3 32 | 33 | # Initializes the CodeQL tools for scanning. 34 | - name: Initialize CodeQL 35 | uses: github/codeql-action/init@v2 36 | with: 37 | languages: ${{ matrix.language }} 38 | # If you wish to specify custom queries, you can do so here or in a config file. 39 | # By default, queries listed here will override any specified in a config file. 40 | # Prefix the list here with "+" to use these queries and those in the config file. 41 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 42 | 43 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 44 | # If this step fails, then you should remove it and run the build manually (see below) 45 | - name: Autobuild 46 | uses: github/codeql-action/autobuild@v2 47 | 48 | # ℹ️ Command-line programs to run using the OS shell. 49 | # 📚 https://git.io/JvXDl 50 | 51 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 52 | # and modify them (or add more) to build your code if your project 53 | # uses a compiled language 54 | 55 | #- run: | 56 | # make bootstrap 57 | # make release 58 | 59 | - name: Perform CodeQL Analysis 60 | uses: github/codeql-action/analyze@v2 61 | -------------------------------------------------------------------------------- /.github/workflows/nodejs.yml: -------------------------------------------------------------------------------- 1 | # This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions 3 | 4 | name: Node.js CI 5 | 6 | on: 7 | push: 8 | branches: [ main ] 9 | pull_request: 10 | branches: [ main ] 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | strategy: 18 | matrix: 19 | node-version: [18.x, 20.x, 22.x] 20 | 21 | steps: 22 | - uses: actions/checkout@v4 23 | - name: Use Node.js ${{ matrix.node-version }} 24 | uses: actions/setup-node@v4 25 | with: 26 | node-version: ${{ matrix.node-version }} 27 | - run: npm ci 28 | - run: npm run build --if-present 29 | - run: npm run pretest 30 | - run: npm run test-slmessage 31 | - run: npm run test-passwordencoder 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Typescript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | .DS_Store 61 | -------------------------------------------------------------------------------- /.markdownlint.json: -------------------------------------------------------------------------------- 1 | { 2 | "default": true, 3 | "no-duplicate-header": { 4 | "siblings_only": true 5 | }, 6 | "line-length": false 7 | } 8 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "node", 9 | "request": "launch", 10 | "name": "Example", 11 | "program": "${workspaceFolder}/example.ts", 12 | "skipFiles": [ 13 | "/**" 14 | ], 15 | "env": { 16 | "DEBUG": "sl:*" 17 | }, 18 | "preLaunchTask": "tsc: build - tsconfig.json", 19 | "outFiles": [ 20 | "${workspaceFolder}/**/*.js", 21 | "!**/node_modules/**" 22 | ] 23 | }, 24 | { 25 | "type": "node", 26 | "request": "launch", 27 | "name": "SLMessage tests", 28 | "program": "${workspaceFolder}/node_modules/mocha/bin/_mocha", 29 | "args": [ 30 | "test/slmessage.spec.js" 31 | ], 32 | "skipFiles": [ 33 | "/**" 34 | ], 35 | "env": { 36 | "DEBUG": "sl:*" 37 | }, 38 | "preLaunchTask": "tsc: build - tsconfig.json", 39 | "outFiles": [ 40 | "${workspaceFolder}/**/*.js", 41 | "!**/node_modules/**" 42 | ] 43 | }, 44 | { 45 | "type": "node", 46 | "request": "launch", 47 | "name": "Password tests", 48 | "program": "${workspaceFolder}/node_modules/mocha/bin/_mocha", 49 | "args": [ 50 | "test/password.spec.js" 51 | ], 52 | "skipFiles": [ 53 | "/**" 54 | ], 55 | "env": { 56 | "DEBUG": "sl:*" 57 | }, 58 | "preLaunchTask": "tsc: build - tsconfig.json", 59 | "outFiles": [ 60 | "${workspaceFolder}/**/*.js", 61 | "!**/node_modules/**" 62 | ] 63 | }, 64 | { 65 | "type": "node", 66 | "request": "launch", 67 | "name": "Finder tests", 68 | "program": "${workspaceFolder}/node_modules/mocha/bin/_mocha", 69 | "args": [ 70 | "test/find.spec.js" 71 | ], 72 | "skipFiles": [ 73 | "/**" 74 | ], 75 | "env": { 76 | "DEBUG": "sl:*" 77 | }, 78 | "preLaunchTask": "tsc: build - tsconfig.json", 79 | "outFiles": [ 80 | "${workspaceFolder}/**/*.js", 81 | "!**/node_modules/**" 82 | ] 83 | }, 84 | { 85 | "type": "node", 86 | "request": "launch", 87 | "name": "SLUnit tests", 88 | "program": "${workspaceFolder}/node_modules/mocha/bin/_mocha", 89 | "args": [ 90 | "test/unit.spec.js" 91 | ], 92 | "skipFiles": [ 93 | "/**" 94 | ], 95 | "env": { 96 | "DEBUG": "sl:*" 97 | }, 98 | "preLaunchTask": "tsc: build - tsconfig.json", 99 | "outFiles": [ 100 | "${workspaceFolder}/**/*.js", 101 | "!**/node_modules/**" 102 | ] 103 | } 104 | ] 105 | } -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## v2.1.1 - 2024-10-07 9 | 10 | ### Fixed 11 | 12 | * Fixed equipment.getCircuitNamesAsync timing out due to not listening to the correct event internally. 13 | 14 | ## v2.1.0 - 2024-06-19 15 | 16 | ### Fixed 17 | 18 | * Fixed bodies.setHeatModeAsync incorrectly subtracting one from the given body index. This is a breaking change if you were correcting for the offset already. 19 | 20 | ## v2.0.0 - 2023-03-10 21 | 22 | This major version number increase comes with many changes under the hood, including a rename of most every method in the library. This adds Promises and Typescript support. See the [Migration guide](https://github.com/parnic/node-screenlogic/wiki/Migration-guide) and [Breaking changes](https://github.com/parnic/node-screenlogic/wiki/Breaking-changes) wiki pages for detailed information. 23 | 24 | ## v1.10.1 - 2022-05-31 25 | 26 | ### Added 27 | 28 | * Added simple "ping" message as a lightweight way to keep the connection alive for a user using the addClient() api. 29 | 30 | ### Fixed 31 | 32 | * Fixed Date parsing from ScreenLogic packets returning the wrong date under specific conditions (such as the last day of the month or during specific hours when javascript month/day assignment order can change other parts of the date). 33 | 34 | ### Changed 35 | 36 | * Improved FindUnits.search() to support being called multiple times. This function issues one UDP broadcast per call, so consumer applications may need to run it in a delayed loop if no units are found on the first request (e.g. when the device running the search or the pool equipment is temporarily disconnected from the network). This is a stateless UDP query, so client applications cannot rely on the error or close events to issue retries. 37 | 38 | ## v1.10.0 - 2022-05-23 39 | 40 | ### Added 41 | 42 | * Added capturing of weather forecast events so that we're not treating it as an unknown message. This also includes full handling for getting weather forecasts from the equipment, but in my experience it's either outdated or not as thorough/reliable as we could get from pretty much any other source, so it remains undocumented for now. 43 | * Added handling of asynchronous chemicalData messages. These are received periodically through the addClient() data push feature. 44 | 45 | ### Fixed 46 | 47 | * Fixed an ugly problem where the library could hang and fail to hand off any more messages if multiple messages were received at the same time (which I've seen happen on lower powered hardware like a Raspberry Pi). This would also cause the internal data buffer to grow unbounded as long as the UnitConnection stayed alive. 48 | 49 | ## v1.9.1 - 2022-05-20 50 | 51 | ### Added 52 | 53 | * Added `close` event to FindUnits, RemoteLogin, and UnitConnection for when the connection to the endpoint has closed. 54 | 55 | ## v1.9.0 - 2022-05-20 56 | 57 | ### Added 58 | 59 | * Added support for getting system chemical history data. This includes pH and ORP readings over time as well as pH and ORP feed on/off times. 60 | 61 | ## v1.8.0 - 2022-04-17 62 | 63 | ### Added 64 | 65 | * Added support for reading ScreenLogic time packets. 66 | * Added support for getting system history data. This includes temperature readings over time as well as circuit on/off changes over time. 67 | 68 | ### Fixed 69 | 70 | * Updated dependencies to safer versions of some packages. 71 | * Fixed day-of-week conversion from Javascript Date objects to ScreenLogic times (SLTimes are 1-based starting on Sunday). 72 | 73 | ### Changed 74 | 75 | * Alphabetized the readme. 76 | 77 | ## v1.7.0 - 2021-10-13 78 | 79 | ### Added 80 | 81 | * Added handling/documentation for the scheduleChanged event (#44). 82 | * Added support for getting and setting the system date/time. 83 | 84 | ### Fixed 85 | 86 | * Documentation updates for `SLGetScheduleData`, more linkage for easy navigation, `addClient`/`removeClient` methods, clarified `coolSetPoint` for spas. 87 | 88 | ## v1.6.1 - 2020-11-23 89 | 90 | ### Added 91 | 92 | * Every call now can optionally specify an ID that will be returned with the result, allowing tracking of simultaneous commands. 93 | 94 | ## v1.6.0 - 2020-07-14 95 | 96 | ### Added 97 | 98 | * Fleshed out the still-undocumented `SLEquipmentConfigurationMessage` with a few more helper methods for interpreting the data inside. 99 | * Helper method for getting a circuit from its device ID on an `SLControllerConfigMessage`. 100 | * Support for getting the status of pumps and setting flow speeds per-pump-per-circuit. 101 | * Constants for interpreting heat command/mode properties on various messages: 102 | * ScreenLogic.HEAT_MODE_OFF 103 | * ScreenLogic.HEAT_MODE_SOLAR 104 | * ScreenLogic.HEAT_MODE_SOLARPREFERRED 105 | * ScreenLogic.HEAT_MODE_HEATPUMP 106 | * ScreenLogic.HEAT_MODE_DONTCHANGE 107 | * Debug logs using the "debug" NPM package. You'll need to run an `npm install` after updating to this version. 108 | * Ability to cancel delays in pool equipment. #20 - thanks @bshep 109 | * Ability to register for push messages from the equipment so the connection can be kept open instead of repeatedly reconnecting and polling for changes. See the `addClient()` and `removeClient()` functions on the `UnitConnection` docs. Thanks @bshep 110 | 111 | ## v1.5.0 - 2020-06-06 112 | 113 | ### Added 114 | 115 | * Added support for adding, deleting, listing, and updating scheduled events - thanks @bshep 116 | * Added egg timer support - thanks @bshep 117 | 118 | ## v1.4.0 - 2020-05-25 119 | 120 | ### Added 121 | 122 | * Support for controlling the salt cell generator's output levels. 123 | * Helper methods for interpreting `controllerType`. 124 | * Experimental support for an Equipment Configuration message (not documented as of yet - `SLEquipmentConfigurationMessage` / `getEquipmentConfiguration()`). This message returns arrays of various information about the equipment, but I don't know how to interpret the information in those arrays yet. Any assistance with decoding this information would be hugely helpful. 125 | * `error` handler on all objects for reacting to unhandled node errors - thanks @schemers 126 | 127 | ### Fixed 128 | 129 | * VSCode "Example" configuration can now be launched on non-Windows platforms. 130 | 131 | ### Changed 132 | 133 | * Minor memory/performance optimizations. 134 | * Running tests no longer changes any state of any pool equipment. 135 | 136 | ## v1.3.1 - 2019-12-27 137 | 138 | ### Added 139 | 140 | * Several methods added to SLControllerConfigMessage for interpreting the equipFlags value. 141 | 142 | ### Fixed 143 | 144 | * server.gatewayName no longer cuts off the last character of the name. #14 - thanks @mikemucc 145 | 146 | ## v1.3.0 - 2019-11-26 147 | 148 | ### Added 149 | 150 | * Ability to set heat setpoint. 151 | * Ability to set heat mode. 152 | * Event for supplying incorrect parameters to `set` functions. 153 | * Ability to send limited selection of light commands. 154 | 155 | ## v1.2.1 - 2019-03-26 156 | 157 | ### Fixed 158 | 159 | * Messages larger than 1024 bytes are now handled properly. 160 | 161 | ## v1.2.0 - 2019-02-22 162 | 163 | ### Added 164 | 165 | * Remote connection through Pentair servers 166 | * Connecting to password-protected systems (this is only enforced by the ScreenLogic system on remote connections) 167 | 168 | ## v1.1.0 - 2018-04-23 169 | 170 | ### Added 171 | 172 | * Ability to set circuit state. 173 | 174 | ### Fixed 175 | 176 | * FindUnits.sendServerBroadcast() was failing in certain environments. 177 | 178 | ## v1.0.1 - 2018-03-31 179 | 180 | ### Added 181 | 182 | * Direct connection support. 183 | 184 | ## v1.0.0 - 2018-03-31 185 | 186 | * Initial release 187 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 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 | -------------------------------------------------------------------------------- /dist/example.d.ts: -------------------------------------------------------------------------------- 1 | export {}; 2 | -------------------------------------------------------------------------------- /dist/example.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const index_1 = require("./index"); 4 | const index_2 = require("./index"); 5 | // import { SLGateWayData } from "./messages/SLGatewayDataMessage"; 6 | // to find units on the local network with the event-based approach: 7 | const finder = new index_1.FindUnits(); 8 | finder.once('serverFound', async (unit) => { 9 | finder.close(); 10 | console.log(`Found unit: ${JSON.stringify(unit)}`); 11 | await connect(unit.gatewayName, unit.address, unit.port); 12 | }); 13 | finder.search(); 14 | // or to connect directly to an already-known unit using async/await (assuming an appropriate environment for await): 15 | // await connect('', '10.0.0.85', 80); 16 | // or to gather all the units that can be found in 1 second using Promises: 17 | // let finder = new FindUnits(); 18 | // finder.searchAsync(1000).then(async (units: LocalUnit[]) => { 19 | // if (units.length > 0) { 20 | // console.log(`Found unit: ${JSON.stringify(units[0])}`); 21 | // await connect(units[0].gatewayName, units[0].address, units[0].port); 22 | // } 23 | // process.exit(0); 24 | // }); 25 | // or to connect to a system remotely with Promises (set your system name and password): 26 | // let systemName = 'Pentair: XX-XX-XX'; 27 | // let password = '1234'; 28 | // let gateway = new RemoteLogin(systemName); 29 | // gateway.connectAsync().then(async (gatewayData: SLGateWayData) => { 30 | // if (!gatewayData || !gatewayData.gatewayFound || gatewayData.ipAddr === '') { 31 | // console.error(`Screenlogic: No unit found called ${systemName}`); 32 | // process.exit(1); 33 | // } 34 | // await connect(systemName, gatewayData.ipAddr, gatewayData.port, password); 35 | // process.exit(0); 36 | // }); 37 | async function connect(gatewayName, ipAddr, port, password) { 38 | const client = new index_2.UnitConnection(); 39 | client.init(gatewayName, ipAddr, port, password); 40 | await client.connectAsync(); 41 | const result = await client.getVersionAsync(); 42 | console.log(` version=${result.version}`); 43 | const state = await client.equipment.getEquipmentStateAsync(42); 44 | console.log(` pool temp=${state.bodies[0].currentTemp}`); 45 | console.log(` air temp=${state.airTemp}`); 46 | console.log(` salt ppm=${state.saltPPM}`); 47 | console.log(` pH=${state.pH}`); 48 | console.log(` saturation=${state.saturation}`); 49 | await client.closeAsync(); 50 | } 51 | //# sourceMappingURL=example.js.map -------------------------------------------------------------------------------- /dist/example.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"example.js","sourceRoot":"","sources":["../example.ts"],"names":[],"mappings":";;AAAA,mCAAgE;AAChE,mCAAyC;AACzC,mEAAmE;AAEnE,oEAAoE;AACpE,MAAM,MAAM,GAAG,IAAI,iBAAS,EAAE,CAAC;AAC/B,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,KAAK,EAAE,IAAe,EAAE,EAAE;IACnD,MAAM,CAAC,KAAK,EAAE,CAAC;IACf,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACnD,MAAM,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;AAC3D,CAAC,CAAC,CAAC;AACH,MAAM,CAAC,MAAM,EAAE,CAAC;AAEhB,qHAAqH;AACrH,sCAAsC;AAEtC,2EAA2E;AAC3E,gCAAgC;AAChC,gEAAgE;AAChE,4BAA4B;AAC5B,8DAA8D;AAC9D,4EAA4E;AAC5E,MAAM;AAEN,qBAAqB;AACrB,MAAM;AAEN,wFAAwF;AACxF,wCAAwC;AACxC,yBAAyB;AACzB,6CAA6C;AAC7C,sEAAsE;AACtE,kFAAkF;AAClF,wEAAwE;AACxE,uBAAuB;AACvB,MAAM;AAEN,+EAA+E;AAE/E,qBAAqB;AACrB,MAAM;AAEN,KAAK,UAAU,OAAO,CAAC,WAAmB,EAAE,MAAc,EAAE,IAAY,EAAE,QAAiB;IACzF,MAAM,MAAM,GAAG,IAAI,sBAAc,EAAE,CAAC;IACpC,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;IACjD,MAAM,MAAM,CAAC,YAAY,EAAE,CAAC;IAE5B,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,eAAe,EAAE,CAAC;IAC9C,OAAO,CAAC,GAAG,CAAC,YAAY,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;IAE1C,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,sBAAsB,CAAC,EAAE,CAAC,CAAC;IAChE,OAAO,CAAC,GAAG,CAAC,cAAc,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;IACzD,OAAO,CAAC,GAAG,CAAC,aAAa,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;IAC1C,OAAO,CAAC,GAAG,CAAC,aAAa,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;IAC1C,OAAO,CAAC,GAAG,CAAC,OAAO,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC;IAC/B,OAAO,CAAC,GAAG,CAAC,eAAe,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC;IAE/C,MAAM,MAAM,CAAC,UAAU,EAAE,CAAC;AAC5B,CAAC"} -------------------------------------------------------------------------------- /dist/index.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | /// 4 | /// 5 | import 'source-map-support/register'; 6 | import * as dgram from 'dgram'; 7 | import { EventEmitter } from 'events'; 8 | import * as net from 'net'; 9 | import * as SLGateway from './messages/SLGatewayDataMessage'; 10 | import { BodyCommands, ChemCommands, ChlorCommands, CircuitCommands, ConnectionCommands, EquipmentCommands, PumpCommands, ScheduleCommands } from './messages/OutgoingMessages'; 11 | import { SLVersionData } from './messages/ConnectionMessage'; 12 | import { SLCircuitNamesData, SLControllerConfigData, SLEquipmentConfigurationData, SLGetCustomNamesData, SLHistoryData, SLWeatherForecastData } from './messages/config/EquipmentConfig'; 13 | import { SLIntellichlorData } from './messages/state/ChlorMessage'; 14 | import { SLChemData, SLChemHistory } from './messages/state/ChemMessage'; 15 | import { SLScheduleData } from './messages/config/ScheduleMessage'; 16 | import { SLPumpStatusData } from './messages/state/PumpMessage'; 17 | import { Inbound, SLMessage, SLSimpleBoolData, SLSimpleNumberData } from './messages/SLMessage'; 18 | import { SLEquipmentStateData, SLSystemTimeData } from './messages/state/EquipmentState'; 19 | export * from './messages/config/ScheduleMessage'; 20 | export * from './messages/config/EquipmentConfig'; 21 | export * from './messages/config/CircuitMessage'; 22 | export * from './messages/config/HeaterMessage'; 23 | export * from './messages/state/ChemMessage'; 24 | export * from './messages/state/ChlorMessage'; 25 | export * from './messages/state/PumpMessage'; 26 | export * from './messages/state/EquipmentState'; 27 | export * from './messages/ConnectionMessage'; 28 | export * from './messages/OutgoingMessages'; 29 | export * from './messages/SLGatewayDataMessage'; 30 | export * from './messages/SLMessage'; 31 | export declare class FindUnits extends EventEmitter { 32 | constructor(); 33 | private finder; 34 | private bound; 35 | private message; 36 | search(): void; 37 | searchAsync(searchTimeMs?: number): Promise; 38 | foundServer(msg: Buffer, remote: dgram.RemoteInfo): void; 39 | sendServerBroadcast(): void; 40 | close(): void; 41 | } 42 | export declare class RemoteLogin extends EventEmitter { 43 | constructor(systemName: string); 44 | systemName: string; 45 | private _client; 46 | private _gateway; 47 | connectAsync(): Promise; 48 | closeAsync(): Promise; 49 | } 50 | export declare class UnitConnection extends EventEmitter { 51 | constructor(); 52 | systemName: string; 53 | private serverPort; 54 | private serverAddress; 55 | private password; 56 | protected client: net.Socket; 57 | private isConnected; 58 | private _clientId; 59 | get clientId(): number; 60 | set clientId(val: number); 61 | private _controllerId; 62 | get controllerId(): number; 63 | set controllerId(val: number); 64 | static controllerType: number; 65 | static expansionsCount: number; 66 | protected _isMock: boolean; 67 | protected _hasAddedClient: boolean; 68 | private _buffer; 69 | private _bufferIdx; 70 | private _senderId; 71 | get senderId(): number; 72 | set senderId(val: number); 73 | controller: Controller; 74 | netTimeout: number; 75 | private _keepAliveDuration; 76 | private _keepAliveTimer; 77 | private _expectedMsgLen; 78 | circuits: Circuit; 79 | equipment: Equipment; 80 | bodies: Body; 81 | chem: Chem; 82 | chlor: Chlor; 83 | schedule: Schedule; 84 | pump: Pump; 85 | reconnectAsync: () => Promise; 86 | initMock(systemName: string, address: string, port: number, password: string, senderId?: number): void; 87 | init(systemName: string, address: string, port: number, password?: string, senderId?: number): void; 88 | initUnit(server: LocalUnit): void; 89 | private _initCommands; 90 | write(bytes: Buffer | string): void; 91 | readMockBytesAsString(hexStr: string): void; 92 | keepAliveAsync(): void; 93 | processData(msg: Buffer): void; 94 | toLogEmit(message: SLMessage, direction: string): void; 95 | closeAsync(): Promise; 96 | connectAsync(): Promise; 97 | loginAsync(challengeString: string, senderId?: number): Promise; 98 | bytesRead(): number; 99 | bytesWritten(): number; 100 | status(): { 101 | destroyed: boolean; 102 | connecting: boolean; 103 | readyState: string; 104 | timeout?: undefined; 105 | } | { 106 | destroyed: boolean; 107 | connecting: boolean; 108 | timeout: number; 109 | readyState: net.SocketReadyState; 110 | }; 111 | getVersionAsync(senderId?: number): Promise; 112 | addClientAsync(clientId?: number, senderId?: number): Promise; 113 | removeClientAsync(clientId?: number, senderId?: number): Promise; 114 | pingServerAsync(senderId?: number): Promise; 115 | onClientMessage(msg: Inbound): void; 116 | } 117 | export declare const screenlogic: UnitConnection; 118 | export declare class Equipment { 119 | protected unit: UnitConnection; 120 | constructor(parent: UnitConnection); 121 | setSystemTimeAsync(date: Date, shouldAdjustForDST: boolean, senderId?: number): Promise; 122 | getWeatherForecastAsync(senderId?: number): Promise; 123 | getHistoryDataAsync(fromTime?: Date, toTime?: Date, senderId?: number): Promise; 124 | getAllCircuitNamesAsync(senderId?: number): Promise; 125 | getNCircuitNamesAsync(senderId?: number): Promise; 126 | getCircuitNamesAsync(size: number, senderId?: number): Promise; 127 | getCircuitDefinitionsAsync(senderId?: number): Promise; 128 | getEquipmentConfigurationAsync(senderId?: number): Promise; 129 | cancelDelayAsync(senderId?: number): Promise; 130 | getSystemTimeAsync(senderId?: number): Promise; 131 | getControllerConfigAsync(senderId?: number): Promise; 132 | getEquipmentStateAsync(senderId?: number): Promise; 133 | getCustomNamesAsync(senderId?: number): Promise; 134 | setCustomNameAsync(idx: number, name: string, senderId?: number): Promise; 135 | } 136 | export declare class Circuit { 137 | protected unit: UnitConnection; 138 | constructor(parent: UnitConnection); 139 | sendLightCommandAsync(command: LightCommands, senderId?: number): Promise; 140 | setCircuitRuntimebyIdAsync(circuitId: number, runTime?: number, senderId?: number): Promise; 141 | setCircuitAsync(circuitId: number, nameIndex: number, circuitFunction: number, circuitInterface: number, freeze: boolean, colorPos: number, senderId?: number): Promise; 142 | setCircuitStateAsync(circuitId: number, circuitState: boolean, senderId?: number): Promise; 143 | } 144 | export declare class Body { 145 | protected unit: UnitConnection; 146 | constructor(parent: UnitConnection); 147 | setSetPointAsync(bodyIndex: BodyIndex, temperature: number, senderId?: number): Promise; 148 | setCoolSetPointAsync(bodyIndex: BodyIndex, temperature: number, senderId?: number): Promise; 149 | setHeatModeAsync(bodyIndex: BodyIndex, heatMode: HeatModes, senderId?: number): Promise; 150 | } 151 | export declare class Pump { 152 | protected unit: UnitConnection; 153 | constructor(parent: UnitConnection); 154 | setPumpSpeedAsync(pumpId: number, circuitId: number, speed: number, isRPMs?: boolean, senderId?: number): Promise; 155 | getPumpStatusAsync(pumpId: number, senderId?: number): Promise; 156 | } 157 | export declare class Schedule { 158 | protected unit: UnitConnection; 159 | constructor(parent: UnitConnection); 160 | setScheduleEventByIdAsync(scheduleId: number, circuitId: number, startTime: number, stopTime: number, dayMask: number, flags: number, heatCmd: number, heatSetPoint: number, senderId?: number): Promise; 161 | addNewScheduleEventAsync(scheduleType: SchedTypes, senderId?: number): Promise; 162 | deleteScheduleEventByIdAsync(scheduleId: number, senderId?: number): Promise; 163 | getScheduleDataAsync(scheduleType: SchedTypes, senderId?: number): Promise; 164 | } 165 | export declare class Chem { 166 | protected unit: UnitConnection; 167 | constructor(parent: UnitConnection); 168 | getChemHistoryDataAsync(fromTime?: Date, toTime?: Date, senderId?: number): Promise; 169 | getChemicalDataAsync(senderId?: number): Promise; 170 | } 171 | export declare class Chlor { 172 | protected unit: UnitConnection; 173 | constructor(parent: UnitConnection); 174 | setIntellichlorOutputAsync(poolOutput: number, spaOutput: number, senderId?: number): Promise; 175 | getIntellichlorConfigAsync(senderId?: number): Promise; 176 | setIntellichlorIsActiveAsync(isActive: boolean, senderId?: number): Promise; 177 | } 178 | export declare enum LightCommands { 179 | LIGHT_CMD_LIGHTS_OFF = 0, 180 | LIGHT_CMD_LIGHTS_ON = 1, 181 | LIGHT_CMD_COLOR_SET = 2, 182 | LIGHT_CMD_COLOR_SYNC = 3, 183 | LIGHT_CMD_COLOR_SWIM = 4, 184 | LIGHT_CMD_COLOR_MODE_PARTY = 5, 185 | LIGHT_CMD_COLOR_MODE_ROMANCE = 6, 186 | LIGHT_CMD_COLOR_MODE_CARIBBEAN = 7, 187 | LIGHT_CMD_COLOR_MODE_AMERICAN = 8, 188 | LIGHT_CMD_COLOR_MODE_SUNSET = 9, 189 | LIGHT_CMD_COLOR_MODE_ROYAL = 10, 190 | LIGHT_CMD_COLOR_SET_SAVE = 11, 191 | LIGHT_CMD_COLOR_SET_RECALL = 12, 192 | LIGHT_CMD_COLOR_BLUE = 13, 193 | LIGHT_CMD_COLOR_GREEN = 14, 194 | LIGHT_CMD_COLOR_RED = 15, 195 | LIGHT_CMD_COLOR_WHITE = 16, 196 | LIGHT_CMD_COLOR_PURPLE = 17 197 | } 198 | export declare enum HeatModes { 199 | HEAT_MODE_OFF = 0, 200 | HEAT_MODE_SOLAR = 1, 201 | HEAT_MODE_SOLARPREFERRED = 2, 202 | HEAT_MODE_HEATPUMP = 3, 203 | HEAT_MODE_HEATER = 3, 204 | HEAT_MODE_DONTCHANGE = 4 205 | } 206 | export declare enum PumpTypes { 207 | Invalid = 0, 208 | PUMP_TYPE_INTELLIFLOVF = 5, 209 | PUMP_TYPE_INTELLIFLOVS = 3, 210 | PUMP_TYPE_INTELLIFLOVSF = 4 211 | } 212 | export declare enum BodyIndex { 213 | POOL = 0, 214 | SPA = 1 215 | } 216 | export interface Controller { 217 | circuits: CircuitCommands; 218 | connection: ConnectionCommands; 219 | equipment: EquipmentCommands; 220 | chlor: ChlorCommands; 221 | chem: ChemCommands; 222 | schedules: ScheduleCommands; 223 | pumps: PumpCommands; 224 | bodies: BodyCommands; 225 | } 226 | export declare enum SchedTypes { 227 | RECURRING = 0, 228 | RUNONCE = 1 229 | } 230 | export interface LocalUnit { 231 | address: string; 232 | type: number; 233 | port: number; 234 | gatewayType: number; 235 | gatewaySubtype: number; 236 | gatewayName: string; 237 | } 238 | -------------------------------------------------------------------------------- /dist/messages/ConnectionMessage.d.ts: -------------------------------------------------------------------------------- 1 | import { Inbound, SLData, SLSimpleBoolData } from './SLMessage'; 2 | export declare class ConnectionMessage { 3 | static decodeChallengeResponse(msg: Inbound): string; 4 | static decodeVersionResponse(msg: Inbound): SLVersionData; 5 | static decodeAddClient(msg: Inbound): SLSimpleBoolData; 6 | static decodeRemoveClient(msg: Inbound): SLSimpleBoolData; 7 | static decodePingClient(msg: Inbound): SLSimpleBoolData; 8 | } 9 | export declare namespace ConnectionMessage { 10 | enum ResponseIDs { 11 | LoginFailure = 13, 12 | Challenge = 15, 13 | Ping = 17, 14 | Login = 28, 15 | UnknownCommand = 30, 16 | BadParameter = 31, 17 | Version = 8121, 18 | AddClient = 12523, 19 | RemoveClient = 12525, 20 | GatewayResponse = 18004 21 | } 22 | } 23 | export interface SLVersionData extends SLData { 24 | version: string; 25 | } 26 | -------------------------------------------------------------------------------- /dist/messages/ConnectionMessage.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.ConnectionMessage = void 0; 4 | class ConnectionMessage { 5 | static decodeChallengeResponse(msg) { 6 | const challengeString = msg.readSLString(); 7 | return challengeString; 8 | } 9 | static decodeVersionResponse(msg) { 10 | const version = msg.readSLString(); 11 | const versionData = { 12 | senderId: msg.senderId, 13 | version 14 | }; 15 | return versionData; 16 | } 17 | static decodeAddClient(msg) { 18 | // ack 19 | const response = { 20 | senderId: msg.senderId, 21 | val: true 22 | }; 23 | return response; 24 | } 25 | static decodeRemoveClient(msg) { 26 | // ack 27 | const response = { 28 | senderId: msg.senderId, 29 | val: true 30 | }; 31 | return response; 32 | } 33 | static decodePingClient(msg) { 34 | // ack 35 | const response = { 36 | senderId: msg.senderId, 37 | val: true 38 | }; 39 | return response; 40 | } 41 | } 42 | exports.ConnectionMessage = ConnectionMessage; 43 | (function (ConnectionMessage) { 44 | let ResponseIDs; 45 | (function (ResponseIDs) { 46 | ResponseIDs[ResponseIDs["LoginFailure"] = 13] = "LoginFailure"; 47 | ResponseIDs[ResponseIDs["Challenge"] = 15] = "Challenge"; 48 | ResponseIDs[ResponseIDs["Ping"] = 17] = "Ping"; 49 | ResponseIDs[ResponseIDs["Login"] = 28] = "Login"; 50 | ResponseIDs[ResponseIDs["UnknownCommand"] = 30] = "UnknownCommand"; 51 | ResponseIDs[ResponseIDs["BadParameter"] = 31] = "BadParameter"; 52 | ResponseIDs[ResponseIDs["Version"] = 8121] = "Version"; 53 | ResponseIDs[ResponseIDs["AddClient"] = 12523] = "AddClient"; 54 | ResponseIDs[ResponseIDs["RemoveClient"] = 12525] = "RemoveClient"; 55 | ResponseIDs[ResponseIDs["GatewayResponse"] = 18004] = "GatewayResponse"; 56 | })(ResponseIDs = ConnectionMessage.ResponseIDs || (ConnectionMessage.ResponseIDs = {})); 57 | })(ConnectionMessage = exports.ConnectionMessage || (exports.ConnectionMessage = {})); 58 | //# sourceMappingURL=ConnectionMessage.js.map -------------------------------------------------------------------------------- /dist/messages/ConnectionMessage.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"ConnectionMessage.js","sourceRoot":"","sources":["../../messages/ConnectionMessage.ts"],"names":[],"mappings":";;;AAIA,MAAa,iBAAiB;IACrB,MAAM,CAAC,uBAAuB,CAAC,GAAY;QAChD,MAAM,eAAe,GAAG,GAAG,CAAC,YAAY,EAAE,CAAC;QAC3C,OAAO,eAAe,CAAC;IACzB,CAAC;IACM,MAAM,CAAC,qBAAqB,CAAC,GAAY;QAC9C,MAAM,OAAO,GAAG,GAAG,CAAC,YAAY,EAAE,CAAC;QACnC,MAAM,WAAW,GAAkB;YACjC,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,OAAO;SACR,CAAC;QACF,OAAO,WAAW,CAAC;IACrB,CAAC;IACM,MAAM,CAAC,eAAe,CAAC,GAAY;QACxC,MAAM;QACN,MAAM,QAAQ,GAAqB;YACjC,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,GAAG,EAAE,IAAI;SACV,CAAC;QACF,OAAO,QAAQ,CAAC;IAClB,CAAC;IACM,MAAM,CAAC,kBAAkB,CAAC,GAAY;QAC3C,MAAM;QACN,MAAM,QAAQ,GAAqB;YACjC,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,GAAG,EAAE,IAAI;SACV,CAAC;QACF,OAAO,QAAQ,CAAC;IAClB,CAAC;IACM,MAAM,CAAC,gBAAgB,CAAC,GAAY;QACzC,MAAM;QACN,MAAM,QAAQ,GAAqB;YACjC,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,GAAG,EAAE,IAAI;SACV,CAAC;QACF,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF;AArCD,8CAqCC;AAED,WAAiB,iBAAiB;IAChC,IAAY,WAWX;IAXD,WAAY,WAAW;QACrB,8DAAiB,CAAA;QACjB,wDAAc,CAAA;QACd,8CAAS,CAAA;QACT,gDAAU,CAAA;QACV,kEAAmB,CAAA;QACnB,8DAAiB,CAAA;QACjB,sDAAc,CAAA;QACd,2DAAiB,CAAA;QACjB,iEAAoB,CAAA;QACpB,uEAAuB,CAAA;IACzB,CAAC,EAXW,WAAW,GAAX,6BAAW,KAAX,6BAAW,QAWtB;AACH,CAAC,EAbgB,iBAAiB,GAAjB,yBAAiB,KAAjB,yBAAiB,QAajC"} -------------------------------------------------------------------------------- /dist/messages/OutgoingMessages.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { Outbound } from './SLMessage'; 3 | import { LightCommands, UnitConnection } from '../index'; 4 | import { rawData } from './config/EquipmentConfig'; 5 | export declare class Commands extends Outbound { 6 | protected unit: UnitConnection; 7 | constructor(unit: UnitConnection, senderId?: number); 8 | } 9 | export declare class ConnectionCommands extends Commands { 10 | sendLoginMessage(password?: Buffer, senderId?: number): ConnectionCommands; 11 | sendChallengeMessage(senderId?: number): ConnectionCommands; 12 | sendVersionMessage(senderId?: number): ConnectionCommands; 13 | sendAddClientMessage(clientId?: number, senderId?: number): ConnectionCommands; 14 | sendRemoveClientMessage(clientId?: number, senderId?: number): ConnectionCommands; 15 | sendPingMessage(senderId?: number): ConnectionCommands; 16 | } 17 | export declare class EquipmentCommands extends Commands { 18 | sendGetEquipmentStateMessage(senderId?: number): EquipmentCommands; 19 | sendGetControllerConfigMessage(senderId?: number): EquipmentCommands; 20 | sendGetNumCircuitNamesMessage(senderId?: number): EquipmentCommands; 21 | sendGetCircuitNamesMessage(idx: number, cnt: number, senderId?: number): EquipmentCommands; 22 | sendGetCircuitDefinitionsMessage(senderId?: number): EquipmentCommands; 23 | sendGetEquipmentConfigurationMessage(senderId?: number): EquipmentCommands; 24 | sendSetEquipmentConfigurationMessageAsync(data: rawData, senderId?: number): EquipmentCommands; 25 | sendGetSystemTimeMessage(senderId?: number): EquipmentCommands; 26 | sendCancelDelayMessage(senderId?: number): EquipmentCommands; 27 | sendGetCustomNamesMessage(senderId?: number): EquipmentCommands; 28 | sendSetCustomNameMessage(idx: number, name: string, senderId?: number): EquipmentCommands; 29 | sendGetWeatherMessage(senderId?: number): EquipmentCommands; 30 | sendSetSystemTimeMessage(date: Date, shouldAdjustForDST: boolean, senderId?: number): EquipmentCommands; 31 | sendGetHistoryMessage(fromTime: Date, toTime: Date, senderId?: number): EquipmentCommands; 32 | } 33 | export declare class CircuitCommands extends Commands { 34 | sendSetCircuitMessage(circuitId: number, nameIndex: number, circuitFunction: number, circuitInterface: number, freeze: boolean, colorPos: number, senderId?: number): CircuitCommands; 35 | sendSetCircuitStateMessage(circuitId: number, circuitState: boolean, senderId?: number): CircuitCommands; 36 | sendIntellibriteMessage(command: LightCommands, senderId?: number): CircuitCommands; 37 | sendSetCircuitRuntimeMessage(circuitId: number, runTime: number, senderId?: number): CircuitCommands; 38 | } 39 | export declare class ChlorCommands extends Commands { 40 | sendSetChlorOutputMessage(poolOutput: number, spaOutput: number, senderId?: number): ChlorCommands; 41 | sendGetSaltCellConfigMessage(senderId?: number): ChlorCommands; 42 | sendSetSaltCellEnableMessage(isActive?: boolean, senderId?: number): ChlorCommands; 43 | } 44 | export declare class ChemCommands extends Commands { 45 | sendGetChemStatusMessage(senderId?: number): ChemCommands; 46 | sendGetChemHistoryMessage(fromTime: Date, toTime: Date, senderId?: number): ChemCommands; 47 | } 48 | export declare class BodyCommands extends Commands { 49 | sendSetPointMessage(bodyType: number, temperature: number, senderId?: number): BodyCommands; 50 | sendCoolSetPointMessage(bodyType: number, temperature: number, senderId?: number): BodyCommands; 51 | sendHeatModeMessage(bodyType: number, heatMode: number, senderId?: number): BodyCommands; 52 | } 53 | export declare class ScheduleCommands extends Commands { 54 | sendGetSchedulesMessage(schedType: number, senderId?: number): ScheduleCommands; 55 | sendAddScheduleEventMessage(schedType: number, senderId?: number): ScheduleCommands; 56 | sendDeleteScheduleEventMessage(schedId: number, senderId?: number): ScheduleCommands; 57 | sendSetScheduleEventMessage(scheduleId: number, circuitId: number, startTime: number, stopTime: number, dayMask: number, flags: number, heatCmd: number, heatSetPoint: number, senderId?: number): ScheduleCommands; 58 | } 59 | export declare class PumpCommands extends Commands { 60 | sendGetPumpStatusMessage(pumpId: number, senderId?: number): PumpCommands; 61 | sendSetPumpSpeed(pumpId: number, circuitId: number, speed: number, isRPMs?: boolean, senderId?: number): PumpCommands; 62 | } 63 | export declare class OutboundGateway extends Outbound { 64 | createSendGatewayMessage(systemName: string, senderId?: number): Buffer; 65 | } 66 | -------------------------------------------------------------------------------- /dist/messages/OutgoingMessages.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.OutboundGateway = exports.PumpCommands = exports.ScheduleCommands = exports.BodyCommands = exports.ChemCommands = exports.ChlorCommands = exports.CircuitCommands = exports.EquipmentCommands = exports.ConnectionCommands = exports.Commands = void 0; 4 | const SLMessage_1 = require("./SLMessage"); 5 | const index_1 = require("../index"); 6 | const EquipmentConfig_1 = require("./config/EquipmentConfig"); 7 | class Commands extends SLMessage_1.Outbound { 8 | constructor(unit, senderId) { 9 | super(unit.controllerId, senderId !== null && senderId !== void 0 ? senderId : unit.senderId); 10 | this.unit = unit; 11 | } 12 | } 13 | exports.Commands = Commands; 14 | class ConnectionCommands extends Commands { 15 | sendLoginMessage(password, senderId) { 16 | this.action = index_1.ConnectionMessage.ResponseIDs.Login - 1; 17 | this.createBaseMessage(senderId); 18 | // this.addHeader(this.senderId, this.messageId) 19 | this.writeInt32LE(348); // schema 20 | this.writeInt32LE(0); // connection type 21 | this.writeSLString('node-screenlogic'); // version 22 | if (!password) { 23 | password = Buffer.alloc(16); 24 | } 25 | if (password.length > 16) { 26 | password = password.slice(0, 16); 27 | } 28 | this.writeSLArray(password); // encoded password. empty/unused for local connections 29 | this.writeInt32LE(2); // procID 30 | this.unit.write(this.toBuffer()); 31 | return this; 32 | } 33 | sendChallengeMessage(senderId) { 34 | this.action = index_1.ConnectionMessage.ResponseIDs.Challenge - 1; 35 | this.createBaseMessage(senderId); 36 | this.unit.write(this.toBuffer()); 37 | return this; 38 | } 39 | sendVersionMessage(senderId) { 40 | this.action = index_1.ConnectionMessage.ResponseIDs.Version - 1; 41 | this.createBaseMessage(senderId); 42 | this.unit.write(this.toBuffer()); 43 | return this; 44 | } 45 | sendAddClientMessage(clientId, senderId) { 46 | this.action = index_1.ConnectionMessage.ResponseIDs.AddClient - 1; 47 | this.createBaseMessage(senderId); 48 | this.writeInt32LE(this.unit.controllerId); 49 | this.writeInt32LE(clientId !== null && clientId !== void 0 ? clientId : this.unit.clientId); 50 | this.unit.write(this.toBuffer()); 51 | return this; 52 | } 53 | sendRemoveClientMessage(clientId, senderId) { 54 | this.action = index_1.ConnectionMessage.ResponseIDs.RemoveClient - 1; 55 | this.createBaseMessage(senderId); 56 | this.writeInt32LE(this.unit.controllerId); 57 | this.writeInt32LE(clientId !== null && clientId !== void 0 ? clientId : this.unit.clientId); 58 | this.unit.write(this.toBuffer()); 59 | return this; 60 | } 61 | sendPingMessage(senderId) { 62 | this.action = index_1.ConnectionMessage.ResponseIDs.Ping - 1; 63 | this.createBaseMessage(senderId); 64 | this.unit.write(this.toBuffer()); 65 | return this; 66 | } 67 | } 68 | exports.ConnectionCommands = ConnectionCommands; 69 | class EquipmentCommands extends Commands { 70 | sendGetEquipmentStateMessage(senderId) { 71 | this.action = index_1.EquipmentStateMessage.ResponseIDs.EquipmentState - 1; 72 | this.createBaseMessage(senderId); 73 | this.writeInt32LE(0); 74 | this.unit.write(this.toBuffer()); 75 | return this; 76 | } 77 | sendGetControllerConfigMessage(senderId) { 78 | this.action = EquipmentConfig_1.EquipmentConfigurationMessage.ResponseIDs.GetControllerConfig - 1; 79 | this.createBaseMessage(senderId); 80 | this.writeInt32LE(0); 81 | this.writeInt32LE(0); 82 | this.unit.write(this.toBuffer()); 83 | return this; 84 | } 85 | sendGetNumCircuitNamesMessage(senderId) { 86 | this.action = EquipmentConfig_1.EquipmentConfigurationMessage.ResponseIDs.NumCircuitNames - 1; 87 | this.createBaseMessage(senderId); 88 | this.writeInt32LE(0); 89 | this.writeInt32LE(0); 90 | this.unit.write(this.toBuffer()); 91 | return this; 92 | } 93 | sendGetCircuitNamesMessage(idx, cnt, senderId) { 94 | this.action = EquipmentConfig_1.EquipmentConfigurationMessage.ResponseIDs.GetCircuitNames; 95 | this.createBaseMessage(senderId); 96 | this.writeInt32LE(0); 97 | this.writeInt32LE(idx); 98 | this.writeInt32LE(cnt); 99 | this.unit.write(this.toBuffer()); 100 | return this; 101 | } 102 | sendGetCircuitDefinitionsMessage(senderId) { 103 | this.action = EquipmentConfig_1.EquipmentConfigurationMessage.ResponseIDs.GetCircuitDefinitions - 1; 104 | this.createBaseMessage(senderId); 105 | this.writeInt32LE(0); 106 | this.writeInt32LE(0); 107 | this.unit.write(this.toBuffer()); 108 | return this; 109 | } 110 | sendGetEquipmentConfigurationMessage(senderId) { 111 | this.action = EquipmentConfig_1.EquipmentConfigurationMessage.ResponseIDs.GetEquipmentConfiguration - 1; 112 | this.createBaseMessage(senderId); 113 | this.writeInt32LE(0); 114 | this.writeInt32LE(0); 115 | this.unit.write(this.toBuffer()); 116 | return this; 117 | } 118 | sendSetEquipmentConfigurationMessageAsync(data, senderId) { 119 | this.action = EquipmentConfig_1.EquipmentConfigurationMessage.ResponseIDs.SetEquipmentConfiguration; //setequipconfg 120 | this.createBaseMessage(senderId); 121 | this.writeInt32LE(0); 122 | this.writeInt32LE(0); 123 | this.unit.write(this.toBuffer()); 124 | return this; 125 | } 126 | sendGetSystemTimeMessage(senderId) { 127 | this.action = index_1.EquipmentStateMessage.ResponseIDs.SystemTime - 1; 128 | this.createBaseMessage(senderId); 129 | this.unit.write(this.toBuffer()); 130 | return this; 131 | } 132 | sendCancelDelayMessage(senderId) { 133 | this.action = index_1.EquipmentStateMessage.ResponseIDs.CancelDelay - 1; 134 | this.createBaseMessage(senderId); 135 | this.writeInt32LE(0); 136 | this.unit.write(this.toBuffer()); 137 | return this; 138 | } 139 | sendGetCustomNamesMessage(senderId) { 140 | this.action = EquipmentConfig_1.EquipmentConfigurationMessage.ResponseIDs.GetCustomNamesAck - 1; 141 | this.createBaseMessage(senderId); 142 | this.writeInt32LE(0); 143 | this.unit.write(this.toBuffer()); 144 | return this; 145 | } 146 | sendSetCustomNameMessage(idx, name, senderId) { 147 | this.action = EquipmentConfig_1.EquipmentConfigurationMessage.ResponseIDs.SetCustomNameAck - 1; 148 | this.createBaseMessage(senderId); 149 | this.writeInt32LE(this.controllerId); 150 | this.writeInt32LE(idx); 151 | this.writeSLString(name); 152 | this.unit.write(this.toBuffer()); 153 | return this; 154 | } 155 | sendGetWeatherMessage(senderId) { 156 | this.action = EquipmentConfig_1.EquipmentConfigurationMessage.ResponseIDs.WeatherForecastAck - 1; 157 | this.createBaseMessage(senderId); 158 | this.writeInt32LE(0); 159 | this.writeInt32LE(0); 160 | this.unit.write(this.toBuffer()); 161 | return this; 162 | } 163 | sendSetSystemTimeMessage(date, shouldAdjustForDST, senderId) { 164 | this.action = index_1.EquipmentStateMessage.ResponseIDs.SetSystemTime - 1; 165 | this.createBaseMessage(senderId); 166 | this.writeSLDateTime(date); 167 | this.writeInt32LE(shouldAdjustForDST ? 1 : 0); 168 | this.unit.write(this.toBuffer()); 169 | return this; 170 | } 171 | sendGetHistoryMessage(fromTime, toTime, senderId) { 172 | this.action = EquipmentConfig_1.EquipmentConfigurationMessage.ResponseIDs.HistoryDataPending - 1; 173 | this.createBaseMessage(senderId); 174 | this.writeInt32LE(this.controllerId); 175 | this.writeSLDateTime(fromTime); 176 | this.writeSLDateTime(toTime); 177 | this.writeInt32LE(senderId !== null && senderId !== void 0 ? senderId : this.senderId); 178 | this.unit.write(this.toBuffer()); 179 | return this; 180 | } 181 | } 182 | exports.EquipmentCommands = EquipmentCommands; 183 | class CircuitCommands extends Commands { 184 | sendSetCircuitMessage(circuitId, nameIndex, circuitFunction, circuitInterface, freeze, colorPos, senderId) { 185 | this.action = index_1.CircuitMessage.ResponseIDs.SetCircuitInfo - 1; 186 | this.createBaseMessage(senderId); 187 | this.writeInt32LE(this.controllerId); 188 | this.writeInt32LE(circuitId + 499); 189 | // normalize to 1 based ids for default names; 100 based for custom names 190 | // circuitArray[i].nameIndex = circuitArray[i].nameIndex < 101 ? circuitArray[i].nameIndex + 1 : circuitArray[i].nameIndex + 99; 191 | this.writeInt32LE(nameIndex < 102 ? nameIndex - 1 : nameIndex - 99); 192 | this.writeInt32LE(circuitFunction); 193 | this.writeInt32LE(circuitInterface); 194 | this.writeInt32LE(freeze ? 1 : 0); // could be other bits; this is a flag 195 | this.writeInt32LE(colorPos); 196 | this.encode(); 197 | this.unit.write(this.toBuffer()); 198 | return this; 199 | } 200 | sendSetCircuitStateMessage(circuitId, circuitState, senderId) { 201 | this.action = index_1.CircuitMessage.ResponseIDs.SetCircuitState - 1; 202 | this.createBaseMessage(senderId); 203 | // this.addHeader(this.senderId, this.messageId); 204 | // this._controllerId = controllerId; 205 | this.writeInt32LE(this.controllerId); 206 | this.writeInt32LE(circuitId + 499); 207 | this.writeInt32LE((circuitState ? 1 : 0) || 0); 208 | this.encode(); 209 | this.unit.write(this.toBuffer()); 210 | return this; 211 | } 212 | sendIntellibriteMessage(command, senderId) { 213 | this.action = index_1.CircuitMessage.ResponseIDs.SetLightState - 1; 214 | this.createBaseMessage(senderId); 215 | this.writeInt32LE(this.unit.controllerId); 216 | this.writeInt32LE(command || 0); 217 | this.unit.write(this.toBuffer()); 218 | return this; 219 | } 220 | sendSetCircuitRuntimeMessage(circuitId, runTime, senderId) { 221 | this.action = index_1.CircuitMessage.ResponseIDs.SetCircuitRunTime - 1; 222 | this.createBaseMessage(senderId); 223 | this.writeInt32LE(this.unit.controllerId); 224 | this.writeInt32LE(circuitId + 499); 225 | this.writeInt32LE(runTime); 226 | this.unit.write(this.toBuffer()); 227 | return this; 228 | } 229 | } 230 | exports.CircuitCommands = CircuitCommands; 231 | class ChlorCommands extends Commands { 232 | sendSetChlorOutputMessage(poolOutput, spaOutput, senderId) { 233 | this.action = index_1.ChlorMessage.ResponseIDs.SetIntellichlorConfig - 1; 234 | this.createBaseMessage(senderId); 235 | this.writeInt32LE(this.unit.controllerId); 236 | this.writeInt32LE(poolOutput || 0); 237 | this.writeInt32LE(spaOutput || 0); 238 | this.writeInt32LE(0); 239 | this.writeInt32LE(0); 240 | this.unit.write(this.toBuffer()); 241 | return this; 242 | } 243 | sendGetSaltCellConfigMessage(senderId) { 244 | this.action = index_1.ChlorMessage.ResponseIDs.GetIntellichlorConfig - 1; 245 | this.createBaseMessage(senderId); 246 | this.writeInt32LE(this.unit.controllerId); 247 | this.unit.write(this.toBuffer()); 248 | return this; 249 | } 250 | sendSetSaltCellEnableMessage(isActive, senderId) { 251 | this.action = index_1.ChlorMessage.ResponseIDs.SetIntellichlorEnabled - 1; 252 | this.createBaseMessage(senderId); 253 | this.writeInt32LE(this.unit.controllerId); 254 | this.writeInt32LE(isActive ? 1 : 0); 255 | this.unit.write(this.toBuffer()); 256 | return this; 257 | } 258 | } 259 | exports.ChlorCommands = ChlorCommands; 260 | class ChemCommands extends Commands { 261 | sendGetChemStatusMessage(senderId) { 262 | this.action = index_1.ChemMessage.ResponseIDs.GetChemicalData - 1; 263 | this.createBaseMessage(senderId); 264 | this.writeInt32LE(0); 265 | this.unit.write(this.toBuffer()); 266 | return this; 267 | } 268 | sendGetChemHistoryMessage(fromTime, toTime, senderId) { 269 | this.action = index_1.ChemMessage.ResponseIDs.HistoryDataPending - 1; 270 | this.createBaseMessage(senderId); 271 | this.writeInt32LE(0); 272 | this.writeSLDateTime(fromTime); 273 | this.writeSLDateTime(toTime); 274 | this.writeInt32LE(senderId !== null && senderId !== void 0 ? senderId : this.senderId); 275 | this.unit.write(this.toBuffer()); 276 | return this; 277 | } 278 | } 279 | exports.ChemCommands = ChemCommands; 280 | class BodyCommands extends Commands { 281 | sendSetPointMessage(bodyType, temperature, senderId) { 282 | this.action = index_1.HeaterMessage.ResponseIDs.SetHeatSetPoint - 1; 283 | this.createBaseMessage(senderId); 284 | this.writeInt32LE(this.unit.controllerId); 285 | this.writeInt32LE(bodyType || 0); 286 | this.writeInt32LE(temperature || 0); 287 | this.unit.write(this.toBuffer()); 288 | return this; 289 | } 290 | sendCoolSetPointMessage(bodyType, temperature, senderId) { 291 | this.action = index_1.HeaterMessage.ResponseIDs.SetCoolSetPoint - 1; 292 | this.createBaseMessage(senderId); 293 | this.writeInt32LE(this.unit.controllerId); 294 | this.writeInt32LE(bodyType || 0); 295 | this.writeInt32LE(temperature || 0); 296 | this.unit.write(this.toBuffer()); 297 | return this; 298 | } 299 | sendHeatModeMessage(bodyType, heatMode, senderId) { 300 | this.action = index_1.HeaterMessage.ResponseIDs.SetHeatMode - 1; 301 | this.createBaseMessage(senderId); 302 | this.writeInt32LE(this.unit.controllerId); 303 | this.writeInt32LE(bodyType || 0); 304 | this.writeInt32LE(heatMode || 0); 305 | this.unit.write(this.toBuffer()); 306 | return this; 307 | } 308 | } 309 | exports.BodyCommands = BodyCommands; 310 | class ScheduleCommands extends Commands { 311 | sendGetSchedulesMessage(schedType, senderId) { 312 | this.action = index_1.ScheduleMessage.ResponseIDs.GetSchedule - 1; 313 | this.createBaseMessage(senderId); 314 | this.writeInt32LE(0); 315 | this.writeInt32LE(schedType); 316 | this.unit.write(this.toBuffer()); 317 | return this; 318 | } 319 | sendAddScheduleEventMessage(schedType, senderId) { 320 | this.action = index_1.ScheduleMessage.ResponseIDs.AddSchedule - 1; 321 | this.createBaseMessage(senderId); 322 | this.writeInt32LE(0); 323 | this.writeInt32LE(schedType); 324 | this.unit.write(this.toBuffer()); 325 | return this; 326 | } 327 | sendDeleteScheduleEventMessage(schedId, senderId) { 328 | this.action = index_1.ScheduleMessage.ResponseIDs.DeleteSchedule - 1; 329 | this.createBaseMessage(senderId); 330 | this.writeInt32LE(this.controllerId); 331 | this.writeInt32LE(schedId + 699); 332 | this.unit.write(this.toBuffer()); 333 | return this; 334 | } 335 | sendSetScheduleEventMessage(scheduleId, circuitId, startTime, stopTime, dayMask, flags, heatCmd, heatSetPoint, senderId) { 336 | this.action = index_1.ScheduleMessage.ResponseIDs.SetSchedule - 1; 337 | this.createBaseMessage(senderId); 338 | this.writeInt32LE(0); 339 | this.writeInt32LE(scheduleId + 699); 340 | this.writeInt32LE(circuitId + 499); 341 | this.writeInt32LE(startTime); 342 | this.writeInt32LE(stopTime); 343 | this.writeInt32LE(dayMask); 344 | this.writeInt32LE(flags); 345 | this.writeInt32LE(heatCmd); 346 | this.writeInt32LE(heatSetPoint); 347 | this.unit.write(this.toBuffer()); 348 | return this; 349 | } 350 | } 351 | exports.ScheduleCommands = ScheduleCommands; 352 | class PumpCommands extends Commands { 353 | sendGetPumpStatusMessage(pumpId, senderId) { 354 | this.action = index_1.PumpMessage.ResponseIDs.PumpStatus - 1; 355 | this.createBaseMessage(senderId); 356 | this.writeInt32LE(this.controllerId); 357 | this.writeInt32LE(pumpId - 1); 358 | this.unit.write(this.toBuffer()); 359 | return this; 360 | } 361 | sendSetPumpSpeed(pumpId, circuitId, speed, isRPMs, senderId) { 362 | this.action = index_1.PumpMessage.ResponseIDs.SetPumpSpeed - 1; 363 | if (typeof isRPMs === 'undefined') { 364 | if (speed < 400) { 365 | isRPMs = false; 366 | } 367 | else 368 | isRPMs = true; 369 | } 370 | const _isRPMs = isRPMs ? 1 : 0; 371 | this.createBaseMessage(senderId); 372 | this.writeInt32LE(this.controllerId); 373 | this.writeInt32LE(pumpId - 1); 374 | this.writeInt32LE(circuitId); // This is indexed to the array of circuits returned in GetPumpStatus 375 | this.writeInt32LE(speed); 376 | this.writeInt32LE(_isRPMs); 377 | this.unit.write(this.toBuffer()); 378 | return this; 379 | } 380 | } 381 | exports.PumpCommands = PumpCommands; 382 | class OutboundGateway extends SLMessage_1.Outbound { 383 | createSendGatewayMessage(systemName, senderId) { 384 | this.action = index_1.ConnectionMessage.ResponseIDs.GatewayResponse - 1; 385 | this.createBaseMessage(senderId); 386 | this.writeSLString(systemName); 387 | this.writeSLString(systemName); 388 | return this.toBuffer(); 389 | } 390 | } 391 | exports.OutboundGateway = OutboundGateway; 392 | //# sourceMappingURL=OutgoingMessages.js.map -------------------------------------------------------------------------------- /dist/messages/OutgoingMessages.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"OutgoingMessages.js","sourceRoot":"","sources":["../../messages/OutgoingMessages.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /dist/messages/SLGatewayDataMessage.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { Inbound } from './SLMessage'; 3 | export declare class SLReceiveGatewayDataMessage extends Inbound { 4 | private data; 5 | constructor(buf: Buffer); 6 | decode(): void; 7 | get(): SLGateWayData; 8 | } 9 | export interface SLGateWayData { 10 | gatewayFound: boolean; 11 | licenseOK: boolean; 12 | ipAddr: string; 13 | port: number; 14 | portOpen: boolean; 15 | relayOn: boolean; 16 | } 17 | -------------------------------------------------------------------------------- /dist/messages/SLGatewayDataMessage.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.SLReceiveGatewayDataMessage = void 0; 4 | const SLMessage_1 = require("./SLMessage"); 5 | class SLReceiveGatewayDataMessage extends SLMessage_1.Inbound { 6 | constructor(buf) { 7 | super(0, 0); 8 | this.readFromBuffer(buf); 9 | this.decode(); 10 | } 11 | decode() { 12 | super.decode(); 13 | const gatewayFound = this._smartBuffer.readUInt8() !== 0; 14 | const licenseOK = this._smartBuffer.readUInt8() !== 0; 15 | const ipAddr = this.readSLString(); 16 | const port = this._smartBuffer.readUInt16LE(); 17 | const portOpen = this._smartBuffer.readUInt8() !== 0; 18 | const relayOn = this._smartBuffer.readUInt8() !== 0; 19 | this.data = { 20 | gatewayFound, 21 | licenseOK, 22 | ipAddr, 23 | port, 24 | portOpen, 25 | relayOn 26 | }; 27 | } 28 | get() { 29 | return this.data; 30 | } 31 | } 32 | exports.SLReceiveGatewayDataMessage = SLReceiveGatewayDataMessage; 33 | //# sourceMappingURL=SLGatewayDataMessage.js.map -------------------------------------------------------------------------------- /dist/messages/SLGatewayDataMessage.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"SLGatewayDataMessage.js","sourceRoot":"","sources":["../../messages/SLGatewayDataMessage.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;;;AAEb,2CAAsC;AAEtC,MAAa,2BAA4B,SAAQ,mBAAO;IAGtD,YAAY,GAAW;QACrB,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACZ,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC;QACzB,IAAI,CAAC,MAAM,EAAE,CAAC;IAChB,CAAC;IAGD,MAAM;QACJ,KAAK,CAAC,MAAM,EAAE,CAAC;QAEf,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;QACzD,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;QACtD,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;QACnC,MAAM,IAAI,GAAG,IAAI,CAAC,YAAY,CAAC,YAAY,EAAE,CAAC;QAC9C,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;QACrD,MAAM,OAAO,GAAG,IAAI,CAAC,YAAY,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;QACpD,IAAI,CAAC,IAAI,GAAG;YACV,YAAY;YACZ,SAAS;YACT,MAAM;YACN,IAAI;YACJ,QAAQ;YACR,OAAO;SACR,CAAC;IAEJ,CAAC;IACD,GAAG;QACD,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;CACF;AAhCD,kEAgCC"} -------------------------------------------------------------------------------- /dist/messages/SLMessage.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { SmartBuffer } from 'smart-buffer'; 3 | export interface SLData { 4 | senderId: number; 5 | } 6 | export interface SLSimpleBoolData extends SLData { 7 | val: boolean; 8 | } 9 | export interface SLSimpleNumberData extends SLData { 10 | val: number; 11 | } 12 | export declare class SLMessage { 13 | static MSG_ID: number; 14 | constructor(controllerId?: number, senderId?: number); 15 | protected _wroteSize: boolean; 16 | action: number; 17 | senderId: number; 18 | controllerId: number; 19 | protected dataLength: number; 20 | protected _smartBuffer: SmartBuffer; 21 | get readOffset(): number; 22 | get length(): number; 23 | static slackForAlignment(val: number): number; 24 | getDayValue(dayName: string): number; 25 | toBuffer(): Buffer; 26 | } 27 | export declare class Inbound extends SLMessage { 28 | readFromBuffer(buf: Buffer): void; 29 | readMessage(buf: Buffer): void; 30 | readSLString(): string; 31 | readSLArray(): Array; 32 | decode(): void; 33 | isBitSet(value: number, bit: number): boolean; 34 | decodeTime(rawTime: number): string; 35 | decodeDayMask(dayMask: number): string[]; 36 | readSLDateTime(): Date; 37 | readUInt8(): number; 38 | readUInt16BE(): number; 39 | readUInt16LE(): number; 40 | readInt32LE(): number; 41 | readUInt32LE(): number; 42 | incrementReadOffset(val: number): void; 43 | toString(): string; 44 | toHexStream(): string; 45 | } 46 | export declare class Outbound extends SLMessage { 47 | constructor(controllerId?: number, senderId?: number, messageId?: number); 48 | createBaseMessage(senderId?: number): void; 49 | addHeader(senderId?: number): void; 50 | encodeDayMask(daysArray: string[]): number; 51 | writeSLDateTime(date: Date): void; 52 | writeInt32LE(val: number): void; 53 | encode(): void; 54 | static getResponseId(): number; 55 | toBuffer(): Buffer; 56 | writeSLString(str: string): void; 57 | writeSLBuffer(buf: Buffer): void; 58 | writeSLArray(arr: Buffer): void; 59 | skipWrite(num: number): void; 60 | encodeTime(stringTime: string): number; 61 | } 62 | -------------------------------------------------------------------------------- /dist/messages/SLMessage.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.Outbound = exports.Inbound = exports.SLMessage = void 0; 4 | const smart_buffer_1 = require("smart-buffer"); 5 | const DAY_VALUES = { 6 | Mon: 0x1, 7 | Tue: 0x2, 8 | Wed: 0x4, 9 | Thu: 0x8, 10 | Fri: 0x10, 11 | Sat: 0x20, 12 | Sun: 0x40, 13 | }; 14 | class SLMessage { 15 | constructor(controllerId, senderId) { 16 | this.senderId = 0; 17 | this.controllerId = 0; 18 | this.controllerId = controllerId !== null && controllerId !== void 0 ? controllerId : 0; 19 | this.senderId = senderId !== null && senderId !== void 0 ? senderId : 0; 20 | } 21 | get readOffset() { return this._smartBuffer.readOffset; } 22 | get length() { return this._smartBuffer.length; } 23 | static slackForAlignment(val) { 24 | return (4 - val % 4) % 4; 25 | } 26 | getDayValue(dayName) { 27 | if (!(dayName in DAY_VALUES)) { 28 | return 0; 29 | } 30 | return DAY_VALUES[dayName]; 31 | } 32 | toBuffer() { 33 | return this._smartBuffer.toBuffer(); 34 | } 35 | } 36 | exports.SLMessage = SLMessage; 37 | class Inbound extends SLMessage { 38 | readFromBuffer(buf) { 39 | this._smartBuffer = smart_buffer_1.SmartBuffer.fromBuffer(buf); 40 | this.decode(); 41 | } 42 | readMessage(buf) { 43 | this._wroteSize = true; 44 | this._smartBuffer.writeBuffer(buf, 0); 45 | this.decode(); 46 | } 47 | readSLString() { 48 | const len = this._smartBuffer.readInt32LE(); 49 | const str = this._smartBuffer.readString(len); 50 | this._smartBuffer.readOffset += SLMessage.slackForAlignment(len); 51 | return str; 52 | } 53 | readSLArray() { 54 | const len = this._smartBuffer.readInt32LE(); 55 | const retval = new Array(len); 56 | for (let i = 0; i < len; i++) { 57 | retval[i] = this._smartBuffer.readUInt8(); 58 | } 59 | this._smartBuffer.readOffset += SLMessage.slackForAlignment(len); 60 | return retval; 61 | } 62 | decode() { 63 | this._smartBuffer.readOffset = 0; 64 | this.senderId = this._smartBuffer.readUInt16LE(); 65 | this.action = this._smartBuffer.readUInt16LE(); 66 | this.dataLength = this._smartBuffer.readInt32LE(); 67 | } 68 | isBitSet(value, bit) { 69 | return ((value >> bit) & 0x1) === 1; 70 | } 71 | decodeTime(rawTime) { 72 | let retVal; 73 | retVal = Math.floor(rawTime / 60) * 100 + rawTime % 60; 74 | retVal = String(retVal).padStart(4, '0'); 75 | return retVal; 76 | } 77 | decodeDayMask(dayMask) { 78 | const days = []; 79 | for (let i = 0; i < 7; i++) { 80 | if (this.isBitSet(dayMask, i)) { 81 | days.push(Object.keys(DAY_VALUES)[i]); 82 | } 83 | } 84 | return days; 85 | } 86 | readSLDateTime() { 87 | const year = this._smartBuffer.readInt16LE(); 88 | const month = this._smartBuffer.readInt16LE() - 1; 89 | this._smartBuffer.readInt16LE(); // day of week 90 | const day = this._smartBuffer.readInt16LE(); 91 | const hour = this._smartBuffer.readInt16LE(); 92 | const minute = this._smartBuffer.readInt16LE(); 93 | const second = this._smartBuffer.readInt16LE(); 94 | const millisecond = this._smartBuffer.readInt16LE(); 95 | const date = new Date(year, month, day, hour, minute, second, millisecond); 96 | return date; 97 | } 98 | readUInt8() { 99 | return this._smartBuffer.readUInt8(); 100 | } 101 | readUInt16BE() { 102 | return this._smartBuffer.readUInt16BE(); 103 | } 104 | readUInt16LE() { 105 | return this._smartBuffer.readUInt16LE(); 106 | } 107 | readInt32LE() { 108 | return this._smartBuffer.readInt32LE(); 109 | } 110 | readUInt32LE() { 111 | return this._smartBuffer.readUInt32LE(); 112 | } 113 | incrementReadOffset(val) { 114 | this._smartBuffer.readOffset = this._smartBuffer.readOffset + val; 115 | } 116 | toString() { 117 | return this._smartBuffer.toString(); 118 | } 119 | toHexStream() { 120 | return this._smartBuffer.toString('hex'); 121 | } 122 | } 123 | exports.Inbound = Inbound; 124 | class Outbound extends SLMessage { 125 | constructor(controllerId, senderId, messageId) { 126 | super(controllerId, senderId); 127 | this.action = messageId; 128 | } 129 | createBaseMessage(senderId) { 130 | this._smartBuffer = new smart_buffer_1.SmartBuffer(); 131 | this.addHeader(senderId); 132 | } 133 | addHeader(senderId) { 134 | this._smartBuffer.writeUInt16LE(senderId !== null && senderId !== void 0 ? senderId : this.senderId); 135 | this._smartBuffer.writeUInt16LE(this.action); 136 | this._wroteSize = false; 137 | } 138 | encodeDayMask(daysArray) { 139 | let dayMask = 0; 140 | for (let i = 0; i < daysArray.length; i++) { 141 | dayMask += this.getDayValue(daysArray[i]); 142 | } 143 | return dayMask; 144 | } 145 | writeSLDateTime(date) { 146 | this._smartBuffer.writeInt16LE(date.getFullYear()); 147 | this._smartBuffer.writeInt16LE(date.getMonth() + 1); 148 | this._smartBuffer.writeInt16LE(date.getDay() + 1); 149 | this._smartBuffer.writeInt16LE(date.getDate()); 150 | this._smartBuffer.writeInt16LE(date.getHours()); 151 | this._smartBuffer.writeInt16LE(date.getMinutes()); 152 | this._smartBuffer.writeInt16LE(date.getSeconds()); 153 | this._smartBuffer.writeInt16LE(date.getMilliseconds()); 154 | } 155 | writeInt32LE(val) { 156 | this._smartBuffer.writeInt32LE(val); 157 | } 158 | encode() { null; } 159 | static getResponseId() { 160 | return this.MSG_ID + 1; 161 | } 162 | toBuffer() { 163 | this.encode(); 164 | if (this._wroteSize === false) { 165 | this._smartBuffer.insertInt32LE(this._smartBuffer.length - 4, 4); 166 | this._wroteSize = true; 167 | } 168 | else { 169 | this._smartBuffer.writeInt32LE(this._smartBuffer.length - 8, 4); 170 | } 171 | return this._smartBuffer.toBuffer(); 172 | } 173 | writeSLString(str) { 174 | this._smartBuffer.writeInt32LE(str.length); 175 | this._smartBuffer.writeString(str); 176 | this.skipWrite(SLMessage.slackForAlignment(str.length)); 177 | } 178 | writeSLBuffer(buf) { 179 | this._smartBuffer.writeInt32LE(buf.length); 180 | this._smartBuffer.writeBuffer(buf); 181 | } 182 | writeSLArray(arr) { 183 | this._smartBuffer.writeInt32LE(arr.length); 184 | for (let i = 0; i < arr.length; i++) { 185 | this._smartBuffer.writeUInt8(arr[i]); 186 | } 187 | this.skipWrite(SLMessage.slackForAlignment(arr.length)); 188 | } 189 | skipWrite(num) { 190 | if (num > 0) { 191 | this._smartBuffer.writeBuffer(Buffer.alloc(num)); 192 | } 193 | } 194 | encodeTime(stringTime) { 195 | return (Number(stringTime.substring(0, 2)) * 60) + Number(stringTime.substring(2, 4)); 196 | } 197 | } 198 | exports.Outbound = Outbound; 199 | //# sourceMappingURL=SLMessage.js.map -------------------------------------------------------------------------------- /dist/messages/SLMessage.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"SLMessage.js","sourceRoot":"","sources":["../../messages/SLMessage.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /dist/messages/config/CircuitMessage.d.ts: -------------------------------------------------------------------------------- 1 | import { Inbound, SLSimpleBoolData } from '../SLMessage'; 2 | export declare class CircuitMessage { 3 | static decodeSetCircuit(msg: Inbound): SLSimpleBoolData; 4 | static decodeSetCircuitState(msg: Inbound): SLSimpleBoolData; 5 | static decodeSetLight(msg: Inbound): SLSimpleBoolData; 6 | static decodeSetCircuitRunTime(msg: Inbound): SLSimpleBoolData; 7 | } 8 | export declare namespace CircuitMessage { 9 | enum ResponseIDs { 10 | LightSequence = 12504, 11 | SetCircuitInfo = 12521, 12 | SetCircuitState = 12531, 13 | SetCircuitRunTime = 12551, 14 | SetLightState = 12557 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /dist/messages/config/CircuitMessage.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.CircuitMessage = void 0; 4 | class CircuitMessage { 5 | static decodeSetCircuit(msg) { 6 | const response = { 7 | senderId: msg.senderId, 8 | val: true 9 | }; 10 | return response; 11 | } 12 | static decodeSetCircuitState(msg) { 13 | // ack 14 | const response = { 15 | senderId: msg.senderId, 16 | val: true 17 | }; 18 | return response; 19 | } 20 | static decodeSetLight(msg) { 21 | // ack 22 | const response = { 23 | senderId: msg.senderId, 24 | val: true 25 | }; 26 | return response; 27 | } 28 | static decodeSetCircuitRunTime(msg) { 29 | // ack 30 | const response = { 31 | senderId: msg.senderId, 32 | val: true 33 | }; 34 | return response; 35 | } 36 | } 37 | exports.CircuitMessage = CircuitMessage; 38 | (function (CircuitMessage) { 39 | let ResponseIDs; 40 | (function (ResponseIDs) { 41 | ResponseIDs[ResponseIDs["LightSequence"] = 12504] = "LightSequence"; 42 | ResponseIDs[ResponseIDs["SetCircuitInfo"] = 12521] = "SetCircuitInfo"; 43 | ResponseIDs[ResponseIDs["SetCircuitState"] = 12531] = "SetCircuitState"; 44 | ResponseIDs[ResponseIDs["SetCircuitRunTime"] = 12551] = "SetCircuitRunTime"; 45 | ResponseIDs[ResponseIDs["SetLightState"] = 12557] = "SetLightState"; 46 | })(ResponseIDs = CircuitMessage.ResponseIDs || (CircuitMessage.ResponseIDs = {})); 47 | })(CircuitMessage = exports.CircuitMessage || (exports.CircuitMessage = {})); 48 | //# sourceMappingURL=CircuitMessage.js.map -------------------------------------------------------------------------------- /dist/messages/config/CircuitMessage.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"CircuitMessage.js","sourceRoot":"","sources":["../../../messages/config/CircuitMessage.ts"],"names":[],"mappings":";;;AAGA,MAAa,cAAc;IAClB,MAAM,CAAC,gBAAgB,CAAC,GAAY;QACzC,MAAM,QAAQ,GAAqB;YACjC,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,GAAG,EAAE,IAAI;SACV,CAAC;QACF,OAAO,QAAQ,CAAC;IAClB,CAAC;IAEM,MAAM,CAAC,qBAAqB,CAAC,GAAY;QAC9C,MAAM;QACN,MAAM,QAAQ,GAAqB;YACjC,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,GAAG,EAAE,IAAI;SACV,CAAC;QACF,OAAO,QAAQ,CAAC;IAClB,CAAC;IACM,MAAM,CAAC,cAAc,CAAC,GAAY;QACvC,MAAM;QACN,MAAM,QAAQ,GAAqB;YACjC,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,GAAG,EAAE,IAAI;SACV,CAAC;QACF,OAAO,QAAQ,CAAC;IAClB,CAAC;IACM,MAAM,CAAC,uBAAuB,CAAC,GAAY;QAChD,MAAM;QACN,MAAM,QAAQ,GAAqB;YACjC,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,GAAG,EAAE,IAAI;SACV,CAAC;QACF,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF;AAjCD,wCAiCC;AAED,WAAiB,cAAc;IAC7B,IAAY,WAMX;IAND,WAAY,WAAW;QACrB,mEAAqB,CAAA;QACrB,qEAAsB,CAAA;QACtB,uEAAuB,CAAA;QACvB,2EAAyB,CAAA;QACzB,mEAAqB,CAAA;IACvB,CAAC,EANW,WAAW,GAAX,0BAAW,KAAX,0BAAW,QAMtB;AACH,CAAC,EARgB,cAAc,GAAd,sBAAc,KAAd,sBAAc,QAQ9B"} -------------------------------------------------------------------------------- /dist/messages/config/EquipmentConfig.d.ts: -------------------------------------------------------------------------------- 1 | import { PumpTypes } from '../../index'; 2 | import { Inbound, SLData, SLSimpleBoolData } from '../SLMessage'; 3 | export declare class EquipmentConfigurationMessage { 4 | static decodeCircuitDefinitions(msg: Inbound): SLCircuitNamesData; 5 | static decodeNCircuitNames(msg: Inbound): number; 6 | static decodeCircuitNames(msg: Inbound): SLCircuitNamesData; 7 | static decodeControllerConfig(msg: Inbound): SLControllerConfigData; 8 | static isEasyTouch(controllerType: number): boolean; 9 | static isIntelliTouch(controllerType: number): boolean; 10 | static isEasyTouchLite(controllerType: number, hwType: number): boolean; 11 | static isDualBody(controllerType: number): boolean; 12 | static isChem2(controllerType: number, hwType: number): boolean; 13 | static decodeSetEquipmentConfigurationAck(msg: Inbound): SLSimpleBoolData; 14 | static decodeSetEquipmentConfiguration(msg: Inbound): SLSetEquipmentConfigurationData; 15 | private static _getNumPumps; 16 | private static _getPumpData; 17 | private static _isValvePresent; 18 | private static _loadHeaterData; 19 | private static _loadValveData; 20 | private static _loadDelayData; 21 | private static _loadMiscData; 22 | private static _loadSpeedData; 23 | private static _loadLightData; 24 | private static _loadRemoteData; 25 | private static _loadSpaFlowData; 26 | static decodeGetEquipmentConfiguration(msg: Inbound): SLEquipmentConfigurationData; 27 | static decodeWeatherMessage(msg: Inbound): SLWeatherForecastData; 28 | static decodeGetHistory(msg: Inbound): SLHistoryData; 29 | getCircuitName(poolConfig: SLEquipmentConfigurationData, circuitIndex: number): string; 30 | static decodeCustomNames(msg: Inbound): SLGetCustomNamesData; 31 | static decodeSetCustomNameAck(msg: Inbound): SLSimpleBoolData; 32 | } 33 | export declare namespace EquipmentConfigurationMessage { 34 | enum ResponseIDs { 35 | WeatherForecastChanged = 9806, 36 | WeatherForecastAck = 9808, 37 | GetHistoryData = 12502, 38 | GetCircuitDefinitions = 12511, 39 | GetControllerConfig = 12533, 40 | HistoryDataPending = 12535, 41 | NumCircuitNames = 12559, 42 | AsyncCircuitNames = 12560, 43 | GetCircuitNames = 12562, 44 | GetCustomNamesAck = 12563, 45 | SetCustomNameAck = 12565, 46 | GetEquipmentConfiguration = 12567, 47 | SetEquipmentConfiguration = 12568, 48 | SetEquipmentConfigurationAck = 12569 49 | } 50 | } 51 | export interface SLControllerConfigData extends SLData { 52 | controllerId: number; 53 | minSetPoint: number[]; 54 | maxSetPoint: number[]; 55 | degC: boolean; 56 | controllerType: number; 57 | circuitCount: number; 58 | hwType: number; 59 | controllerData: number; 60 | equipment: Equipment; 61 | genCircuitName: string; 62 | interfaceTabFlags: number; 63 | circuitArray: Circuit[]; 64 | colorCount: number; 65 | colorArray: SLNameColor[]; 66 | pumpCircCount: number; 67 | pumpCircArray: number[]; 68 | showAlarms: number; 69 | } 70 | export interface Equipment { 71 | POOL_SOLARPRESENT: boolean; 72 | POOL_SOLARHEATPUMP: boolean; 73 | POOL_CHLORPRESENT: boolean; 74 | POOL_IBRITEPRESENT: boolean; 75 | POOL_IFLOWPRESENT0: boolean; 76 | POOL_IFLOWPRESENT1: boolean; 77 | POOL_IFLOWPRESENT2: boolean; 78 | POOL_IFLOWPRESENT3: boolean; 79 | POOL_IFLOWPRESENT4: boolean; 80 | POOL_IFLOWPRESENT5: boolean; 81 | POOL_IFLOWPRESENT6: boolean; 82 | POOL_IFLOWPRESENT7: boolean; 83 | POOL_NO_SPECIAL_LIGHTS: boolean; 84 | POOL_HEATPUMPHASCOOL: boolean; 85 | POOL_MAGICSTREAMPRESENT: boolean; 86 | POOL_ICHEMPRESENT: boolean; 87 | } 88 | export interface Circuit { 89 | circuitId: number; 90 | name: string; 91 | nameIndex: number; 92 | function: number; 93 | interface: number; 94 | freeze: number; 95 | colorSet?: number; 96 | colorPos?: number; 97 | colorStagger?: number; 98 | eggTimer: number; 99 | deviceId: number; 100 | } 101 | export interface SLColor { 102 | r: number; 103 | g: number; 104 | b: number; 105 | } 106 | export interface SLNameColor { 107 | name: string; 108 | color: SLColor; 109 | } 110 | export interface SLSetEquipmentConfigurationData extends SLData { 111 | pumps: Pump[]; 112 | heaterConfig: HeaterConfig; 113 | valves: Valves[]; 114 | delays: Delays; 115 | misc: Misc; 116 | lights: Lights; 117 | highSpeedCircuits: number[]; 118 | remotes: SLRemoteData; 119 | numPumps: number; 120 | } 121 | export interface SLEquipmentConfigurationData extends SLData { 122 | controllerType: number; 123 | hardwareType: number; 124 | expansionsCount: number; 125 | version: number; 126 | pumps: Pump[]; 127 | heaterConfig: HeaterConfig; 128 | valves: Valves[]; 129 | delays: Delays; 130 | misc: Misc; 131 | remotes: SLRemoteData; 132 | highSpeedCircuits: number[]; 133 | lights: Lights; 134 | spaFlow: SpaFlow; 135 | numPumps: number; 136 | rawData: rawData; 137 | } 138 | export interface SLRemoteData { 139 | fourButton: number[]; 140 | tenButton: number[][]; 141 | quickTouch: number[]; 142 | } 143 | export interface rawData { 144 | versionData: number[]; 145 | highSpeedCircuitData: number[]; 146 | valveData: number[]; 147 | remoteData: number[]; 148 | heaterConfigData: number[]; 149 | delayData: number[]; 150 | macroData: number[]; 151 | miscData: number[]; 152 | lightData: number[]; 153 | pumpData: number[]; 154 | sgData: number[]; 155 | spaFlowData: number[]; 156 | } 157 | export interface PumpCircuit { 158 | id: number; 159 | circuit: number; 160 | speed?: number; 161 | flow?: number; 162 | units: number; 163 | } 164 | export interface Pump { 165 | id: number; 166 | type: number; 167 | pentairType: PumpTypes; 168 | name: string; 169 | address: number; 170 | circuits: PumpCircuit[]; 171 | primingSpeed: number; 172 | primingTime: number; 173 | minSpeed: number; 174 | maxSpeed: number; 175 | speedStepSize: number; 176 | backgroundCircuit: number; 177 | filterSize: number; 178 | turnovers: number; 179 | manualFilterGPM: number; 180 | minFlow: number; 181 | maxFlow: number; 182 | flowStepSize: number; 183 | maxSystemTime: number; 184 | maxPressureIncrease: number; 185 | backwashFlow: number; 186 | backwashTime: number; 187 | rinseTime: number; 188 | vacuumFlow: number; 189 | vacuumTime: number; 190 | } 191 | export interface Lights { 192 | allOnAllOff: number[]; 193 | } 194 | export interface SpaFlow { 195 | isActive: boolean; 196 | pumpId: number; 197 | stepSize: number; 198 | } 199 | export interface HeaterConfig { 200 | body1SolarPresent: boolean; 201 | body2SolarPresent: boolean; 202 | thermaFloCoolPresent: boolean; 203 | solarHeatPumpPresent: boolean; 204 | thermaFloPresent: boolean; 205 | units: number; 206 | } 207 | export interface Delays { 208 | poolPumpOnDuringHeaterCooldown: boolean; 209 | spaPumpOnDuringHeaterCooldown: boolean; 210 | pumpOffDuringValveAction: boolean; 211 | } 212 | export interface Misc { 213 | intelliChem: boolean; 214 | manualHeat: boolean; 215 | } 216 | export interface Valves { 217 | loadCenterIndex: number; 218 | valveIndex: number; 219 | valveName: string; 220 | loadCenterName: string; 221 | deviceId: number; 222 | sCircuit?: string; 223 | } 224 | export interface SLWeatherForecastData extends SLData { 225 | version: number; 226 | zip: string; 227 | lastUpdate: Date; 228 | lastRequest: Date; 229 | dateText: string; 230 | text: string; 231 | currentTemperature: number; 232 | humidity: number; 233 | wind: string; 234 | pressure: number; 235 | dewPoint: number; 236 | windChill: number; 237 | visibility: number; 238 | dayData: SLWeatherForecastDayData[]; 239 | sunrise: number; 240 | sunset: number; 241 | } 242 | export interface SLWeatherForecastDayData { 243 | dayTime: Date; 244 | highTemp: number; 245 | lowTemp: number; 246 | text: string; 247 | } 248 | export interface TimeTimePointPairs { 249 | on: Date; 250 | off: Date; 251 | } 252 | export interface TimeTempPointPairs { 253 | time: Date; 254 | temp: number; 255 | } 256 | export interface SLHistoryData extends SLData { 257 | airTemps: TimeTempPointPairs[]; 258 | poolTemps: TimeTempPointPairs[]; 259 | poolSetPointTemps: TimeTempPointPairs[]; 260 | spaTemps: TimeTempPointPairs[]; 261 | spaSetPointTemps: TimeTempPointPairs[]; 262 | poolRuns: TimeTimePointPairs[]; 263 | spaRuns: TimeTimePointPairs[]; 264 | solarRuns: TimeTimePointPairs[]; 265 | heaterRuns: TimeTimePointPairs[]; 266 | lightRuns: TimeTimePointPairs[]; 267 | } 268 | export interface SLCircuitIdName { 269 | id: number; 270 | circuitName: string; 271 | } 272 | export interface SLCircuitNamesData extends SLData { 273 | circuits: SLCircuitIdName[]; 274 | } 275 | export interface SLGetCustomNamesData extends SLData { 276 | names: string[]; 277 | } 278 | -------------------------------------------------------------------------------- /dist/messages/config/HeaterMessage.d.ts: -------------------------------------------------------------------------------- 1 | import { Inbound, SLSimpleBoolData } from '../SLMessage'; 2 | export declare class HeaterMessage { 3 | static decodeSetHeatSetPoint(msg: Inbound): SLSimpleBoolData; 4 | static decodeCoolSetHeatSetPoint(msg: Inbound): SLSimpleBoolData; 5 | static decodeSetHeatModePoint(msg: Inbound): SLSimpleBoolData; 6 | } 7 | export declare namespace HeaterMessage { 8 | enum ResponseIDs { 9 | SetHeatSetPoint = 12529, 10 | SetHeatMode = 12539, 11 | SetCoolSetPoint = 12591 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /dist/messages/config/HeaterMessage.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.HeaterMessage = void 0; 4 | class HeaterMessage { 5 | static decodeSetHeatSetPoint(msg) { 6 | // ack 7 | const response = { 8 | senderId: msg.senderId, 9 | val: true 10 | }; 11 | return response; 12 | } 13 | static decodeCoolSetHeatSetPoint(msg) { 14 | // ack 15 | const response = { 16 | senderId: msg.senderId, 17 | val: true 18 | }; 19 | return response; 20 | } 21 | static decodeSetHeatModePoint(msg) { 22 | // ack 23 | const response = { 24 | senderId: msg.senderId, 25 | val: true 26 | }; 27 | return response; 28 | } 29 | } 30 | exports.HeaterMessage = HeaterMessage; 31 | (function (HeaterMessage) { 32 | let ResponseIDs; 33 | (function (ResponseIDs) { 34 | ResponseIDs[ResponseIDs["SetHeatSetPoint"] = 12529] = "SetHeatSetPoint"; 35 | ResponseIDs[ResponseIDs["SetHeatMode"] = 12539] = "SetHeatMode"; 36 | ResponseIDs[ResponseIDs["SetCoolSetPoint"] = 12591] = "SetCoolSetPoint"; 37 | })(ResponseIDs = HeaterMessage.ResponseIDs || (HeaterMessage.ResponseIDs = {})); 38 | })(HeaterMessage = exports.HeaterMessage || (exports.HeaterMessage = {})); 39 | //# sourceMappingURL=HeaterMessage.js.map -------------------------------------------------------------------------------- /dist/messages/config/HeaterMessage.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"HeaterMessage.js","sourceRoot":"","sources":["../../../messages/config/HeaterMessage.ts"],"names":[],"mappings":";;;AAEA,MAAa,aAAa;IACjB,MAAM,CAAC,qBAAqB,CAAC,GAAY;QAC9C,MAAM;QACN,MAAM,QAAQ,GAAqB;YACjC,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,GAAG,EAAE,IAAI;SACV,CAAC;QACF,OAAO,QAAQ,CAAC;IAClB,CAAC;IACM,MAAM,CAAC,yBAAyB,CAAC,GAAY;QAClD,MAAM;QACN,MAAM,QAAQ,GAAqB;YACjC,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,GAAG,EAAE,IAAI;SACV,CAAC;QACF,OAAO,QAAQ,CAAC;IAClB,CAAC;IACM,MAAM,CAAC,sBAAsB,CAAC,GAAY;QAC/C,MAAM;QACN,MAAM,QAAQ,GAAqB;YACjC,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,GAAG,EAAE,IAAI;SACV,CAAC;QACF,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF;AAzBD,sCAyBC;AAED,WAAiB,aAAa;IAC5B,IAAY,WAIX;IAJD,WAAY,WAAW;QACrB,uEAAuB,CAAA;QACvB,+DAAmB,CAAA;QACnB,uEAAuB,CAAA;IACzB,CAAC,EAJW,WAAW,GAAX,yBAAW,KAAX,yBAAW,QAItB;AACH,CAAC,EANgB,aAAa,GAAb,qBAAa,KAAb,qBAAa,QAM7B"} -------------------------------------------------------------------------------- /dist/messages/config/ScheduleMessage.d.ts: -------------------------------------------------------------------------------- 1 | import { Inbound, SLData, SLSimpleBoolData, SLSimpleNumberData } from '../SLMessage'; 2 | export declare class ScheduleMessage { 3 | static decodeGetScheduleMessage(msg: Inbound): SLScheduleData; 4 | static decodeAddSchedule(msg: Inbound): SLSimpleNumberData; 5 | static decodeDeleteSchedule(msg: Inbound): SLSimpleBoolData; 6 | static decodeSetSchedule(msg: Inbound): SLSimpleBoolData; 7 | } 8 | export declare namespace ScheduleMessage { 9 | enum ResponseIDs { 10 | ScheduleChanged = 12501, 11 | GetSchedule = 12543, 12 | AddSchedule = 12545, 13 | DeleteSchedule = 12547, 14 | SetSchedule = 12549 15 | } 16 | } 17 | export interface SLScheduleDatum { 18 | scheduleId: number; 19 | circuitId: number; 20 | startTime: string; 21 | stopTime: string; 22 | dayMask: number; 23 | flags: number; 24 | heatCmd: number; 25 | heatSetPoint: number; 26 | days: string[]; 27 | } 28 | export interface SLScheduleData extends SLData { 29 | data: SLScheduleDatum[]; 30 | } 31 | -------------------------------------------------------------------------------- /dist/messages/config/ScheduleMessage.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.ScheduleMessage = void 0; 4 | class ScheduleMessage { 5 | static decodeGetScheduleMessage(msg) { 6 | const eventCount = msg.readUInt32LE(); 7 | const data = []; 8 | for (let i = 0; i < eventCount; i++) { 9 | const scheduleId = msg.readUInt32LE() - 699; 10 | const circuitId = msg.readUInt32LE() - 499; 11 | const startTime = msg.decodeTime(msg.readUInt32LE()); 12 | const stopTime = msg.decodeTime(msg.readUInt32LE()); 13 | const dayMask = msg.readUInt32LE(); 14 | const flags = msg.readUInt32LE(); 15 | const heatCmd = msg.readUInt32LE(); 16 | const heatSetPoint = msg.readUInt32LE(); 17 | const days = msg.decodeDayMask(dayMask); 18 | const event = { 19 | scheduleId, 20 | circuitId, 21 | startTime, 22 | stopTime, 23 | dayMask, 24 | flags, 25 | heatCmd, 26 | heatSetPoint, 27 | days 28 | }; 29 | data.push(event); 30 | } 31 | const result = { 32 | senderId: msg.senderId, 33 | data 34 | }; 35 | return result; 36 | } 37 | static decodeAddSchedule(msg) { 38 | const response = { 39 | senderId: msg.senderId, 40 | val: msg.readUInt32LE() - 699 41 | }; 42 | return response; 43 | } 44 | static decodeDeleteSchedule(msg) { 45 | // ack 46 | const response = { 47 | senderId: msg.senderId, 48 | val: true 49 | }; 50 | return response; 51 | } 52 | static decodeSetSchedule(msg) { 53 | // ack 54 | const response = { 55 | senderId: msg.senderId, 56 | val: true 57 | }; 58 | return response; 59 | } 60 | } 61 | exports.ScheduleMessage = ScheduleMessage; 62 | (function (ScheduleMessage) { 63 | let ResponseIDs; 64 | (function (ResponseIDs) { 65 | ResponseIDs[ResponseIDs["ScheduleChanged"] = 12501] = "ScheduleChanged"; 66 | ResponseIDs[ResponseIDs["GetSchedule"] = 12543] = "GetSchedule"; 67 | ResponseIDs[ResponseIDs["AddSchedule"] = 12545] = "AddSchedule"; 68 | ResponseIDs[ResponseIDs["DeleteSchedule"] = 12547] = "DeleteSchedule"; 69 | ResponseIDs[ResponseIDs["SetSchedule"] = 12549] = "SetSchedule"; 70 | })(ResponseIDs = ScheduleMessage.ResponseIDs || (ScheduleMessage.ResponseIDs = {})); 71 | })(ScheduleMessage = exports.ScheduleMessage || (exports.ScheduleMessage = {})); 72 | //# sourceMappingURL=ScheduleMessage.js.map -------------------------------------------------------------------------------- /dist/messages/config/ScheduleMessage.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"ScheduleMessage.js","sourceRoot":"","sources":["../../../messages/config/ScheduleMessage.ts"],"names":[],"mappings":";;;AAGA,MAAa,eAAe;IACnB,MAAM,CAAC,wBAAwB,CAAC,GAAY;QACjD,MAAM,UAAU,GAAG,GAAG,CAAC,YAAY,EAAE,CAAC;QACtC,MAAM,IAAI,GAAsB,EAAE,CAAC;QACnC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,EAAE,CAAC,EAAE,EAAE;YACnC,MAAM,UAAU,GAAG,GAAG,CAAC,YAAY,EAAE,GAAG,GAAG,CAAC;YAC5C,MAAM,SAAS,GAAG,GAAG,CAAC,YAAY,EAAE,GAAG,GAAG,CAAC;YAC3C,MAAM,SAAS,GAAG,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC,CAAC;YACrD,MAAM,QAAQ,GAAG,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC,CAAC;YACpD,MAAM,OAAO,GAAG,GAAG,CAAC,YAAY,EAAE,CAAC;YACnC,MAAM,KAAK,GAAG,GAAG,CAAC,YAAY,EAAE,CAAC;YACjC,MAAM,OAAO,GAAG,GAAG,CAAC,YAAY,EAAE,CAAC;YACnC,MAAM,YAAY,GAAG,GAAG,CAAC,YAAY,EAAE,CAAC;YACxC,MAAM,IAAI,GAAG,GAAG,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;YACxC,MAAM,KAAK,GAAoB;gBAC7B,UAAU;gBACV,SAAS;gBACT,SAAS;gBACT,QAAQ;gBACR,OAAO;gBACP,KAAK;gBACL,OAAO;gBACP,YAAY;gBACZ,IAAI;aACL,CAAC;YACF,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;SAClB;QACD,MAAM,MAAM,GAAmB;YAC7B,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,IAAI;SACL,CAAC;QACF,OAAO,MAAM,CAAC;IAChB,CAAC;IACM,MAAM,CAAC,iBAAiB,CAAC,GAAY;QAC1C,MAAM,QAAQ,GAAuB;YACnC,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,GAAG,EAAE,GAAG,CAAC,YAAY,EAAE,GAAG,GAAG;SAC9B,CAAC;QACF,OAAO,QAAQ,CAAC;IAClB,CAAC;IACM,MAAM,CAAC,oBAAoB,CAAC,GAAY;QAC7C,MAAM;QACN,MAAM,QAAQ,GAAqB;YACjC,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,GAAG,EAAE,IAAI;SACV,CAAC;QACF,OAAO,QAAQ,CAAC;IAClB,CAAC;IACM,MAAM,CAAC,iBAAiB,CAAC,GAAY;QAC1C,MAAM;QACN,MAAM,QAAQ,GAAqB;YACjC,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,GAAG,EAAE,IAAI;SACV,CAAC;QACF,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF;AAxDD,0CAwDC;AAED,WAAiB,eAAe;IAC9B,IAAY,WAMX;IAND,WAAY,WAAW;QACrB,uEAAuB,CAAA;QACvB,+DAAmB,CAAA;QACnB,+DAAmB,CAAA;QACnB,qEAAsB,CAAA;QACtB,+DAAmB,CAAA;IACrB,CAAC,EANW,WAAW,GAAX,2BAAW,KAAX,2BAAW,QAMtB;AACH,CAAC,EARgB,eAAe,GAAf,uBAAe,KAAf,uBAAe,QAQ/B"} -------------------------------------------------------------------------------- /dist/messages/state/ChemMessage.d.ts: -------------------------------------------------------------------------------- 1 | import { Inbound, SLData } from '../SLMessage'; 2 | export declare class ChemMessage { 3 | static decodeChemDataMessage(msg: Inbound): SLChemData; 4 | static decodecChemHistoryMessage(msg: Inbound): SLChemHistory; 5 | } 6 | export declare namespace ChemMessage { 7 | enum ResponseIDs { 8 | AsyncChemicalData = 12505, 9 | ChemicalHistoryData = 12506, 10 | HistoryDataPending = 12597, 11 | GetChemicalData = 12593 12 | } 13 | } 14 | export interface SLChemData extends SLData { 15 | isValid: boolean; 16 | pH: number; 17 | orp: number; 18 | pHSetPoint: number; 19 | orpSetPoint: number; 20 | pHTankLevel: number; 21 | orpTankLevel: number; 22 | saturation: number; 23 | calcium: number; 24 | cyanuricAcid: number; 25 | alkalinity: number; 26 | saltPPM: number; 27 | temperature: number; 28 | balance: number; 29 | corrosive: boolean; 30 | scaling: boolean; 31 | error: boolean; 32 | } 33 | export interface TimePHPointsPairs { 34 | time: Date; 35 | pH: number; 36 | } 37 | export interface TimeORPPointsPairs { 38 | time: Date; 39 | orp: number; 40 | } 41 | export interface TimeTimePointsPairs { 42 | on: Date; 43 | off: Date; 44 | } 45 | export interface SLChemHistory { 46 | phPoints: TimePHPointsPairs[]; 47 | orpPoints: TimeORPPointsPairs[]; 48 | phRuns: TimeTimePointsPairs[]; 49 | orpRuns: TimeTimePointsPairs[]; 50 | } 51 | -------------------------------------------------------------------------------- /dist/messages/state/ChemMessage.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.ChemMessage = void 0; 4 | class ChemMessage { 5 | static decodeChemDataMessage(msg) { 6 | let isValid = false; 7 | const sentinel = msg.readInt32LE(); 8 | if (sentinel === 42) { 9 | isValid = true; 10 | // msg._smartBuffer.readOffset++; 11 | msg.incrementReadOffset(1); 12 | const pH = msg.readUInt16BE() / 100; 13 | const orp = msg.readUInt16BE(); 14 | const pHSetPoint = msg.readUInt16BE() / 100; 15 | const orpSetPoint = msg.readUInt16BE(); 16 | // msg._smartBuffer.readOffset += 12; 17 | msg.incrementReadOffset(12); 18 | const pHTankLevel = msg.readUInt8(); 19 | const orpTankLevel = msg.readUInt8(); 20 | let saturation = msg.readUInt8(); 21 | if ((saturation & 128) !== 0) { 22 | saturation = -(256 - saturation); 23 | } 24 | saturation /= 100; 25 | const calcium = msg.readUInt16BE(); 26 | const cyanuricAcid = msg.readUInt16BE(); 27 | const alkalinity = msg.readUInt16BE(); 28 | const salt = msg.readUInt16LE(); 29 | const saltPPM = salt * 50; 30 | const temperature = msg.readUInt8(); 31 | msg.incrementReadOffset(2); 32 | const balance = msg.readUInt8(); 33 | const corrosive = (balance & 1) !== 0; 34 | const scaling = (balance & 2) !== 0; 35 | const error = (salt & 128) !== 0; 36 | const data = { 37 | senderId: msg.senderId, 38 | isValid, 39 | pH, 40 | orp, 41 | pHSetPoint, 42 | orpSetPoint, 43 | pHTankLevel, 44 | orpTankLevel, 45 | saturation, 46 | calcium, 47 | cyanuricAcid, 48 | alkalinity, 49 | saltPPM, 50 | temperature, 51 | balance, 52 | corrosive, 53 | scaling, 54 | error 55 | }; 56 | return data; 57 | } 58 | } 59 | static decodecChemHistoryMessage(msg) { 60 | const readTimePHPointsPairs = () => { 61 | const retval = []; 62 | // 4 bytes for the length 63 | if (msg.length >= msg.readOffset + 4) { 64 | const points = msg.readInt32LE(); 65 | // 16 bytes per time, 4 bytes per pH reading 66 | if (msg.length >= msg.readOffset + (points * (16 + 4))) { 67 | for (let i = 0; i < points; i++) { 68 | const time = msg.readSLDateTime(); 69 | const pH = msg.readInt32LE() / 100; 70 | retval.push({ 71 | time: time, 72 | pH: pH, 73 | }); 74 | } 75 | } 76 | } 77 | return retval; 78 | }; 79 | const readTimeORPPointsPairs = () => { 80 | const retval = []; 81 | // 4 bytes for the length 82 | if (msg.length >= msg.readOffset + 4) { 83 | const points = msg.readInt32LE(); 84 | // 16 bytes per time, 4 bytes per ORP reading 85 | if (msg.length >= msg.readOffset + (points * (16 + 4))) { 86 | for (let i = 0; i < points; i++) { 87 | const time = msg.readSLDateTime(); 88 | const orp = msg.readInt32LE(); 89 | retval.push({ 90 | time: time, 91 | orp: orp, 92 | }); 93 | } 94 | } 95 | } 96 | return retval; 97 | }; 98 | const readTimeTimePointsPairs = () => { 99 | const retval = []; 100 | // 4 bytes for the length 101 | if (msg.length >= msg.readOffset + 4) { 102 | const points = msg.readInt32LE(); 103 | // 16 bytes per on time, 16 bytes per off time 104 | if (msg.length >= msg.readOffset + (points * (16 + 16))) { 105 | for (let i = 0; i < points; i++) { 106 | const onTime = msg.readSLDateTime(); 107 | const offTime = msg.readSLDateTime(); 108 | retval.push({ 109 | on: onTime, 110 | off: offTime, 111 | }); 112 | } 113 | } 114 | } 115 | return retval; 116 | }; 117 | const data = { 118 | phPoints: readTimePHPointsPairs(), 119 | orpPoints: readTimeORPPointsPairs(), 120 | phRuns: readTimeTimePointsPairs(), 121 | orpRuns: readTimeTimePointsPairs() 122 | }; 123 | return data; 124 | } 125 | } 126 | exports.ChemMessage = ChemMessage; 127 | (function (ChemMessage) { 128 | let ResponseIDs; 129 | (function (ResponseIDs) { 130 | ResponseIDs[ResponseIDs["AsyncChemicalData"] = 12505] = "AsyncChemicalData"; 131 | ResponseIDs[ResponseIDs["ChemicalHistoryData"] = 12506] = "ChemicalHistoryData"; 132 | ResponseIDs[ResponseIDs["HistoryDataPending"] = 12597] = "HistoryDataPending"; 133 | ResponseIDs[ResponseIDs["GetChemicalData"] = 12593] = "GetChemicalData"; 134 | })(ResponseIDs = ChemMessage.ResponseIDs || (ChemMessage.ResponseIDs = {})); 135 | })(ChemMessage = exports.ChemMessage || (exports.ChemMessage = {})); 136 | //# sourceMappingURL=ChemMessage.js.map -------------------------------------------------------------------------------- /dist/messages/state/ChemMessage.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"ChemMessage.js","sourceRoot":"","sources":["../../../messages/state/ChemMessage.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /dist/messages/state/ChlorMessage.d.ts: -------------------------------------------------------------------------------- 1 | import { Inbound, SLData, SLSimpleBoolData } from '../SLMessage'; 2 | export declare class ChlorMessage { 3 | static decodeIntellichlorConfig(msg: Inbound): SLIntellichlorData; 4 | static decodeSetIntellichlorConfig(msg: Inbound): SLSimpleBoolData; 5 | static decodeSetEnableIntellichlorConfig(msg: Inbound): SLSimpleBoolData; 6 | } 7 | export declare namespace ChlorMessage { 8 | enum ResponseIDs { 9 | GetIntellichlorConfig = 12573, 10 | SetIntellichlorEnabled = 12575, 11 | SetIntellichlorConfig = 12577 12 | } 13 | } 14 | export interface SLIntellichlorData extends SLData { 15 | installed: boolean; 16 | status: number; 17 | poolSetPoint: number; 18 | spaSetPoint: number; 19 | salt: number; 20 | flags: number; 21 | superChlorTimer: number; 22 | } 23 | -------------------------------------------------------------------------------- /dist/messages/state/ChlorMessage.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.ChlorMessage = void 0; 4 | class ChlorMessage { 5 | static decodeIntellichlorConfig(msg) { 6 | const data = { 7 | senderId: msg.senderId, 8 | installed: msg.readInt32LE() === 1, 9 | status: msg.readInt32LE(), 10 | poolSetPoint: msg.readInt32LE(), 11 | spaSetPoint: msg.readInt32LE(), 12 | salt: msg.readInt32LE() * 50, 13 | flags: msg.readInt32LE(), 14 | superChlorTimer: msg.readInt32LE() 15 | }; 16 | return data; 17 | } 18 | static decodeSetIntellichlorConfig(msg) { 19 | // ack 20 | const response = { 21 | senderId: msg.senderId, 22 | val: true 23 | }; 24 | return response; 25 | } 26 | static decodeSetEnableIntellichlorConfig(msg) { 27 | // ack 28 | const response = { 29 | senderId: msg.senderId, 30 | val: true 31 | }; 32 | return response; 33 | } 34 | } 35 | exports.ChlorMessage = ChlorMessage; 36 | (function (ChlorMessage) { 37 | let ResponseIDs; 38 | (function (ResponseIDs) { 39 | ResponseIDs[ResponseIDs["GetIntellichlorConfig"] = 12573] = "GetIntellichlorConfig"; 40 | ResponseIDs[ResponseIDs["SetIntellichlorEnabled"] = 12575] = "SetIntellichlorEnabled"; 41 | ResponseIDs[ResponseIDs["SetIntellichlorConfig"] = 12577] = "SetIntellichlorConfig"; 42 | })(ResponseIDs = ChlorMessage.ResponseIDs || (ChlorMessage.ResponseIDs = {})); 43 | })(ChlorMessage = exports.ChlorMessage || (exports.ChlorMessage = {})); 44 | //# sourceMappingURL=ChlorMessage.js.map -------------------------------------------------------------------------------- /dist/messages/state/ChlorMessage.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"ChlorMessage.js","sourceRoot":"","sources":["../../../messages/state/ChlorMessage.ts"],"names":[],"mappings":";;;AAGA,MAAa,YAAY;IAChB,MAAM,CAAC,wBAAwB,CAAC,GAAY;QACjD,MAAM,IAAI,GAAuB;YAC/B,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,SAAS,EAAE,GAAG,CAAC,WAAW,EAAE,KAAK,CAAC;YAClC,MAAM,EAAE,GAAG,CAAC,WAAW,EAAE;YACzB,YAAY,EAAE,GAAG,CAAC,WAAW,EAAE;YAC/B,WAAW,EAAE,GAAG,CAAC,WAAW,EAAE;YAC9B,IAAI,EAAE,GAAG,CAAC,WAAW,EAAE,GAAG,EAAE;YAC5B,KAAK,EAAE,GAAG,CAAC,WAAW,EAAE;YACxB,eAAe,EAAE,GAAG,CAAC,WAAW,EAAE;SACnC,CAAC;QACF,OAAO,IAAI,CAAC;IACd,CAAC;IACM,MAAM,CAAC,2BAA2B,CAAC,GAAY;QACpD,MAAM;QACN,MAAM,QAAQ,GAAqB;YACjC,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,GAAG,EAAE,IAAI;SACV,CAAC;QACF,OAAO,QAAQ,CAAC;IAClB,CAAC;IACM,MAAM,CAAC,iCAAiC,CAAC,GAAY;QAC1D,MAAM;QACN,MAAM,QAAQ,GAAqB;YACjC,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,GAAG,EAAE,IAAI;SACV,CAAC;QACF,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF;AA9BD,oCA8BC;AAED,WAAiB,YAAY;IAC3B,IAAY,WAIX;IAJD,WAAY,WAAW;QACrB,mFAA6B,CAAA;QAC7B,qFAA8B,CAAA;QAC9B,mFAA6B,CAAA;IAC/B,CAAC,EAJW,WAAW,GAAX,wBAAW,KAAX,wBAAW,QAItB;AACH,CAAC,EANgB,YAAY,GAAZ,oBAAY,KAAZ,oBAAY,QAM5B"} -------------------------------------------------------------------------------- /dist/messages/state/EquipmentState.d.ts: -------------------------------------------------------------------------------- 1 | import { Inbound, SLData, SLSimpleBoolData } from '../SLMessage'; 2 | import { Delays, Misc, SLCircuitIdName, SLHistoryData, SLWeatherForecastData, Valves } from '../config/EquipmentConfig'; 3 | export declare class EquipmentStateMessage { 4 | static decodeEquipmentStateResponse(msg: Inbound): SLEquipmentStateData; 5 | static decodeSystemTime(msg: Inbound): SLSystemTimeData; 6 | static decodeCancelDelay(msg: Inbound): SLSimpleBoolData; 7 | static decodeSetSystemTime(msg: Inbound): SLSimpleBoolData; 8 | static decodeEquipmentConfiguration(msg: Inbound): { 9 | controllerType: number; 10 | hardwareType: number; 11 | expansionsCount: number; 12 | version: number; 13 | heaterConfig: { 14 | body1SolarPresent: boolean; 15 | body1HeatPumpPresent: boolean; 16 | body2SolarPresent: boolean; 17 | thermaFloPresent: boolean; 18 | thermaFloCoolPresent: boolean; 19 | }; 20 | valves: Valves[]; 21 | delays: Delays; 22 | misc: Misc; 23 | speed: SLCircuitIdName[]; 24 | }; 25 | static decodeWeatherMessage(msg: Inbound): SLWeatherForecastData; 26 | static decodeGetHistory(msg: Inbound): SLHistoryData; 27 | static decodeGeneric(msg: Inbound): void; 28 | } 29 | export declare namespace EquipmentStateMessage { 30 | enum ResponseIDs { 31 | SystemTime = 8111, 32 | SetSystemTime = 8113, 33 | AsyncEquipmentState = 12500, 34 | EquipmentState = 12527, 35 | CancelDelay = 12581 36 | } 37 | } 38 | export interface SLEquipmentStateData extends SLData { 39 | panelMode: number; 40 | freezeMode: number; 41 | remotes: number; 42 | poolDelay: number; 43 | spaDelay: number; 44 | cleanerDelay: number; 45 | airTemp: number; 46 | bodiesCount: number; 47 | bodies: SLEquipmentBodyState[]; 48 | circuitArray: SLEquipmentCircuitArrayState[]; 49 | pH: number; 50 | orp: number; 51 | saturation: number; 52 | saltPPM: number; 53 | pHTank: number; 54 | orpTank: number; 55 | alarms: number; 56 | } 57 | export interface SLEquipmentBodyState { 58 | id: number; 59 | currentTemp: number; 60 | heatStatus: number; 61 | setPoint: number; 62 | coolSetPoint: number; 63 | heatMode: number; 64 | } 65 | export interface SLEquipmentCircuitArrayState { 66 | id: number; 67 | state: number; 68 | colorSet: number; 69 | colorPos: number; 70 | colorStagger: number; 71 | delay: number; 72 | } 73 | export interface SLSystemTimeData { 74 | date: Date; 75 | year: number; 76 | month: number; 77 | dayOfWeek: number; 78 | day: number; 79 | hour: number; 80 | minute: number; 81 | second: number; 82 | millisecond: number; 83 | adjustForDST: boolean; 84 | } 85 | -------------------------------------------------------------------------------- /dist/messages/state/EquipmentState.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"EquipmentState.js","sourceRoot":"","sources":["../../../messages/state/EquipmentState.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /dist/messages/state/PumpMessage.d.ts: -------------------------------------------------------------------------------- 1 | import { PumpTypes } from '../../index'; 2 | import { Inbound, SLData, SLSimpleBoolData } from '../SLMessage'; 3 | export declare class PumpMessage { 4 | static decodePumpStatus(msg: Inbound): SLPumpStatusData; 5 | static decodeSetPumpSpeed(msg: Inbound): SLSimpleBoolData; 6 | } 7 | export declare namespace PumpMessage { 8 | enum ResponseIDs { 9 | PumpStatus = 12585, 10 | SetPumpSpeed = 12587 11 | } 12 | } 13 | export interface SLPumpStatusData extends SLData { 14 | pumpCircuits: SLPumpCircuitData[]; 15 | pumpType: PumpTypes; 16 | isRunning: boolean; 17 | pumpWatts: number; 18 | pumpRPMs: number; 19 | pumpUnknown1: number; 20 | pumpGPMs: number; 21 | pumpUnknown2: number; 22 | } 23 | export interface SLPumpCircuitData { 24 | circuitId: number; 25 | speed: number; 26 | isRPMs: boolean; 27 | } 28 | -------------------------------------------------------------------------------- /dist/messages/state/PumpMessage.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.PumpMessage = void 0; 4 | const index_1 = require("../../index"); 5 | class PumpMessage { 6 | static decodePumpStatus(msg) { 7 | // This pump type seems to be different: 8 | // 1 = VF 9 | // 2 = VS 10 | // 3 = VSF 11 | // The equipmentConfig message gives more specifics on the pump type 12 | const _pumpType = msg.readUInt32LE(); 13 | const pumpType = _pumpType === 1 ? index_1.PumpTypes.PUMP_TYPE_INTELLIFLOVF : _pumpType === 2 ? index_1.PumpTypes.PUMP_TYPE_INTELLIFLOVS : _pumpType === 3 ? index_1.PumpTypes.PUMP_TYPE_INTELLIFLOVSF : _pumpType; 14 | const isRunning = msg.readUInt32LE() !== 0; // 0, 1, or 4294967295 (FF FF FF FF) 15 | const pumpWatts = msg.readUInt32LE(); 16 | const pumpRPMs = msg.readUInt32LE(); 17 | const pumpUnknown1 = msg.readUInt32LE(); // Always 0 18 | const pumpGPMs = msg.readUInt32LE(); 19 | const pumpUnknown2 = msg.readUInt32LE(); // Always 255 20 | const pumpCircuits = []; 21 | for (let i = 0; i < 8; i++) { 22 | const _pumpCirc = { 23 | circuitId: msg.readUInt32LE(), 24 | speed: msg.readUInt32LE(), 25 | isRPMs: msg.readUInt32LE() !== 0 // 1 for RPMs; 0 for GPMs 26 | }; 27 | pumpCircuits.push(_pumpCirc); 28 | } 29 | const data = { 30 | senderId: msg.senderId, 31 | pumpCircuits, 32 | pumpType, 33 | isRunning, 34 | pumpWatts, 35 | pumpRPMs, 36 | pumpUnknown1, 37 | pumpGPMs, 38 | pumpUnknown2 39 | }; 40 | return data; 41 | } 42 | static decodeSetPumpSpeed(msg) { 43 | // ack 44 | const response = { 45 | senderId: msg.senderId, 46 | val: true 47 | }; 48 | return response; 49 | } 50 | } 51 | exports.PumpMessage = PumpMessage; 52 | (function (PumpMessage) { 53 | let ResponseIDs; 54 | (function (ResponseIDs) { 55 | ResponseIDs[ResponseIDs["PumpStatus"] = 12585] = "PumpStatus"; 56 | ResponseIDs[ResponseIDs["SetPumpSpeed"] = 12587] = "SetPumpSpeed"; 57 | })(ResponseIDs = PumpMessage.ResponseIDs || (PumpMessage.ResponseIDs = {})); 58 | })(PumpMessage = exports.PumpMessage || (exports.PumpMessage = {})); 59 | //# sourceMappingURL=PumpMessage.js.map -------------------------------------------------------------------------------- /dist/messages/state/PumpMessage.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"PumpMessage.js","sourceRoot":"","sources":["../../../messages/state/PumpMessage.ts"],"names":[],"mappings":";;;AAAA,uCAAwC;AAIxC,MAAa,WAAW;IACf,MAAM,CAAC,gBAAgB,CAAC,GAAY;QACzC,wCAAwC;QACxC,SAAS;QACT,SAAS;QACT,UAAU;QACV,oEAAoE;QACpE,MAAM,SAAS,GAAG,GAAG,CAAC,YAAY,EAAE,CAAC;QACrC,MAAM,QAAQ,GAAG,SAAS,KAAK,CAAC,CAAC,CAAC,CAAC,iBAAS,CAAC,sBAAsB,CAAC,CAAC,CAAC,SAAS,KAAK,CAAC,CAAC,CAAC,CAAC,iBAAS,CAAC,sBAAsB,CAAC,CAAC,CAAC,SAAS,KAAK,CAAC,CAAC,CAAC,CAAC,iBAAS,CAAC,uBAAuB,CAAC,CAAC,CAAC,SAAS,CAAC;QAC3L,MAAM,SAAS,GAAG,GAAG,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC,CAAC,oCAAoC;QAChF,MAAM,SAAS,GAAG,GAAG,CAAC,YAAY,EAAE,CAAC;QACrC,MAAM,QAAQ,GAAG,GAAG,CAAC,YAAY,EAAE,CAAC;QACpC,MAAM,YAAY,GAAG,GAAG,CAAC,YAAY,EAAE,CAAC,CAAC,WAAW;QACpD,MAAM,QAAQ,GAAG,GAAG,CAAC,YAAY,EAAE,CAAC;QACpC,MAAM,YAAY,GAAG,GAAG,CAAC,YAAY,EAAE,CAAC,CAAC,aAAa;QAEtD,MAAM,YAAY,GAAG,EAAE,CAAC;QACxB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;YAC1B,MAAM,SAAS,GAAsB;gBACnC,SAAS,EAAE,GAAG,CAAC,YAAY,EAAE;gBAC7B,KAAK,EAAE,GAAG,CAAC,YAAY,EAAE;gBACzB,MAAM,EAAE,GAAG,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC,yBAAyB;aAC3D,CAAC;YACF,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;SAC9B;QACD,MAAM,IAAI,GAAqB;YAC7B,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,YAAY;YACZ,QAAQ;YACR,SAAS;YACT,SAAS;YACT,QAAQ;YACR,YAAY;YACZ,QAAQ;YACR,YAAY;SACb,CAAC;QACF,OAAO,IAAI,CAAC;IACd,CAAC;IACM,MAAM,CAAC,kBAAkB,CAAC,GAAW;QAC1C,MAAM;QACN,MAAM,QAAQ,GAAqB;YACjC,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,GAAG,EAAE,IAAI;SACV,CAAC;QACF,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF;AA9CD,kCA8CC;AAED,WAAiB,WAAW;IAC1B,IAAY,WAGX;IAHD,WAAY,WAAW;QACrB,6DAAkB,CAAA;QAClB,iEAAoB,CAAA;IACtB,CAAC,EAHW,WAAW,GAAX,uBAAW,KAAX,uBAAW,QAGtB;AACH,CAAC,EALgB,WAAW,GAAX,mBAAW,KAAX,mBAAW,QAK3B"} -------------------------------------------------------------------------------- /dist/utils/PasswordEncoder.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | export declare class HLEncoder { 3 | constructor(password: string); 4 | private kd; 5 | private ke; 6 | private tk; 7 | private bKeyInit; 8 | private iROUNDS; 9 | createArray(length: number, max_length: number): any[]; 10 | getEncryptedPassword(cls: string): Buffer; 11 | makeKey(sChallengeStr: string[]): void; 12 | makeBlock(str: string[], byFill: number): any[]; 13 | makeKeyFromBlock(block: number[]): void; 14 | encryptBlock(block: number[]): number[]; 15 | encrypt(source: string[]): Buffer; 16 | encryptData(data: number[]): Buffer; 17 | } 18 | -------------------------------------------------------------------------------- /example.ts: -------------------------------------------------------------------------------- 1 | import { FindUnits, LocalUnit/*, RemoteLogin*/ } from './index'; 2 | import { UnitConnection } from './index'; 3 | // import { SLGateWayData } from "./messages/SLGatewayDataMessage"; 4 | 5 | // to find units on the local network with the event-based approach: 6 | const finder = new FindUnits(); 7 | finder.once('serverFound', async (unit: LocalUnit) => { 8 | finder.close(); 9 | console.log(`Found unit: ${JSON.stringify(unit)}`); 10 | await connect(unit.gatewayName, unit.address, unit.port); 11 | }); 12 | finder.search(); 13 | 14 | // or to connect directly to an already-known unit using async/await (assuming an appropriate environment for await): 15 | // await connect('', '10.0.0.85', 80); 16 | 17 | // or to gather all the units that can be found in 1 second using Promises: 18 | // let finder = new FindUnits(); 19 | // finder.searchAsync(1000).then(async (units: LocalUnit[]) => { 20 | // if (units.length > 0) { 21 | // console.log(`Found unit: ${JSON.stringify(units[0])}`); 22 | // await connect(units[0].gatewayName, units[0].address, units[0].port); 23 | // } 24 | 25 | // process.exit(0); 26 | // }); 27 | 28 | // or to connect to a system remotely with Promises (set your system name and password): 29 | // let systemName = 'Pentair: XX-XX-XX'; 30 | // let password = '1234'; 31 | // let gateway = new RemoteLogin(systemName); 32 | // gateway.connectAsync().then(async (gatewayData: SLGateWayData) => { 33 | // if (!gatewayData || !gatewayData.gatewayFound || gatewayData.ipAddr === '') { 34 | // console.error(`Screenlogic: No unit found called ${systemName}`); 35 | // process.exit(1); 36 | // } 37 | 38 | // await connect(systemName, gatewayData.ipAddr, gatewayData.port, password); 39 | 40 | // process.exit(0); 41 | // }); 42 | 43 | async function connect(gatewayName: string, ipAddr: string, port: number, password?: string) { 44 | const client = new UnitConnection(); 45 | client.init(gatewayName, ipAddr, port, password); 46 | await client.connectAsync(); 47 | 48 | const result = await client.getVersionAsync(); 49 | console.log(` version=${result.version}`); 50 | 51 | const state = await client.equipment.getEquipmentStateAsync(42); 52 | console.log(` pool temp=${state.bodies[0].currentTemp}`); 53 | console.log(` air temp=${state.airTemp}`); 54 | console.log(` salt ppm=${state.saltPPM}`); 55 | console.log(` pH=${state.pH}`); 56 | console.log(` saturation=${state.saturation}`); 57 | 58 | await client.closeAsync(); 59 | } 60 | -------------------------------------------------------------------------------- /messages/ConnectionMessage.ts: -------------------------------------------------------------------------------- 1 | 2 | import { Inbound, SLData, SLSimpleBoolData } from './SLMessage'; 3 | 4 | 5 | export class ConnectionMessage{ 6 | public static decodeChallengeResponse(msg: Inbound): string { 7 | const challengeString = msg.readSLString(); 8 | return challengeString; 9 | } 10 | public static decodeVersionResponse(msg: Inbound): SLVersionData { 11 | const version = msg.readSLString(); 12 | const versionData: SLVersionData = { 13 | senderId: msg.senderId, 14 | version 15 | }; 16 | return versionData; 17 | } 18 | public static decodeAddClient(msg: Inbound): SLSimpleBoolData { 19 | // ack 20 | const response: SLSimpleBoolData = { 21 | senderId: msg.senderId, 22 | val: true 23 | }; 24 | return response; 25 | } 26 | public static decodeRemoveClient(msg: Inbound): SLSimpleBoolData { 27 | // ack 28 | const response: SLSimpleBoolData = { 29 | senderId: msg.senderId, 30 | val: true 31 | }; 32 | return response; 33 | } 34 | public static decodePingClient(msg: Inbound): SLSimpleBoolData { 35 | // ack 36 | const response: SLSimpleBoolData = { 37 | senderId: msg.senderId, 38 | val: true 39 | }; 40 | return response; 41 | } 42 | } 43 | 44 | export namespace ConnectionMessage { // eslint-disable-line @typescript-eslint/no-namespace 45 | export enum ResponseIDs { 46 | LoginFailure = 13, 47 | Challenge = 15, 48 | Ping = 17, 49 | Login = 28, 50 | UnknownCommand = 30, 51 | BadParameter = 31, 52 | Version = 8121, 53 | AddClient = 12523, 54 | RemoveClient = 12525, 55 | GatewayResponse = 18004, 56 | } 57 | } 58 | 59 | export interface SLVersionData extends SLData { 60 | version: string 61 | } 62 | -------------------------------------------------------------------------------- /messages/OutgoingMessages.ts: -------------------------------------------------------------------------------- 1 | import { Outbound } from './SLMessage'; 2 | import { ChemMessage, ChlorMessage, CircuitMessage, ConnectionMessage, EquipmentStateMessage, HeaterMessage, LightCommands, PumpMessage, ScheduleMessage, UnitConnection } from '../index'; 3 | import { EquipmentConfigurationMessage, rawData } from './config/EquipmentConfig'; 4 | 5 | export class Commands extends Outbound { 6 | protected unit: UnitConnection; 7 | constructor(unit: UnitConnection, senderId?: number) { 8 | super(unit.controllerId, senderId ?? unit.senderId); 9 | this.unit = unit; 10 | } 11 | } 12 | 13 | export class ConnectionCommands extends Commands { 14 | public sendLoginMessage(password?: Buffer, senderId?: number): ConnectionCommands { 15 | this.action = ConnectionMessage.ResponseIDs.Login - 1; 16 | this.createBaseMessage(senderId); 17 | // this.addHeader(this.senderId, this.messageId) 18 | this.writeInt32LE(348); // schema 19 | this.writeInt32LE(0); // connection type 20 | this.writeSLString('node-screenlogic'); // version 21 | 22 | if (!password) { 23 | password = Buffer.alloc(16); 24 | } 25 | if (password.length > 16) { 26 | password = password.slice(0, 16); 27 | } 28 | this.writeSLArray(password); // encoded password. empty/unused for local connections 29 | 30 | this.writeInt32LE(2); // procID 31 | this.unit.write(this.toBuffer()); 32 | return this; 33 | } 34 | 35 | public sendChallengeMessage(senderId?: number): ConnectionCommands { 36 | this.action = ConnectionMessage.ResponseIDs.Challenge - 1; 37 | this.createBaseMessage(senderId); 38 | this.unit.write(this.toBuffer()); 39 | return this; 40 | } 41 | public sendVersionMessage(senderId?: number): ConnectionCommands { 42 | this.action = ConnectionMessage.ResponseIDs.Version - 1; 43 | this.createBaseMessage(senderId); 44 | this.unit.write(this.toBuffer()); 45 | return this; 46 | } 47 | public sendAddClientMessage(clientId?: number, senderId?: number): ConnectionCommands { 48 | this.action = ConnectionMessage.ResponseIDs.AddClient - 1; 49 | this.createBaseMessage(senderId); 50 | this.writeInt32LE(this.unit.controllerId); 51 | this.writeInt32LE(clientId ?? this.unit.clientId); 52 | this.unit.write(this.toBuffer()); 53 | return this; 54 | } 55 | public sendRemoveClientMessage(clientId?: number, senderId?: number): ConnectionCommands { 56 | this.action = ConnectionMessage.ResponseIDs.RemoveClient - 1; 57 | this.createBaseMessage(senderId); 58 | this.writeInt32LE(this.unit.controllerId); 59 | this.writeInt32LE(clientId ?? this.unit.clientId); 60 | this.unit.write(this.toBuffer()); 61 | return this; 62 | } 63 | public sendPingMessage(senderId?: number): ConnectionCommands { 64 | this.action = ConnectionMessage.ResponseIDs.Ping - 1; 65 | this.createBaseMessage(senderId); 66 | this.unit.write(this.toBuffer()); 67 | return this; 68 | } 69 | } 70 | 71 | 72 | export class EquipmentCommands extends Commands { 73 | public sendGetEquipmentStateMessage(senderId?: number): EquipmentCommands { 74 | this.action = EquipmentStateMessage.ResponseIDs.EquipmentState - 1; 75 | this.createBaseMessage(senderId); 76 | this.writeInt32LE(0); 77 | this.unit.write(this.toBuffer()); 78 | return this; 79 | } 80 | public sendGetControllerConfigMessage(senderId?: number): EquipmentCommands { 81 | this.action = EquipmentConfigurationMessage.ResponseIDs.GetControllerConfig - 1; 82 | this.createBaseMessage(senderId); 83 | this.writeInt32LE(0); 84 | this.writeInt32LE(0); 85 | this.unit.write(this.toBuffer()); 86 | return this; 87 | } 88 | public sendGetNumCircuitNamesMessage(senderId?: number): EquipmentCommands { 89 | this.action = EquipmentConfigurationMessage.ResponseIDs.NumCircuitNames - 1; 90 | this.createBaseMessage(senderId); 91 | this.writeInt32LE(0); 92 | this.writeInt32LE(0); 93 | this.unit.write(this.toBuffer()); 94 | return this; 95 | } 96 | public sendGetCircuitNamesMessage(idx: number, cnt: number, senderId?: number): EquipmentCommands { 97 | this.action = EquipmentConfigurationMessage.ResponseIDs.GetCircuitNames; 98 | this.createBaseMessage(senderId); 99 | this.writeInt32LE(0); 100 | this.writeInt32LE(idx); 101 | this.writeInt32LE(cnt); 102 | this.unit.write(this.toBuffer()); 103 | return this; 104 | } 105 | public sendGetCircuitDefinitionsMessage(senderId?: number): EquipmentCommands { 106 | this.action = EquipmentConfigurationMessage.ResponseIDs.GetCircuitDefinitions - 1; 107 | this.createBaseMessage(senderId); 108 | this.writeInt32LE(0); 109 | this.writeInt32LE(0); 110 | this.unit.write(this.toBuffer()); 111 | return this; 112 | } 113 | public sendGetEquipmentConfigurationMessage(senderId?: number): EquipmentCommands { 114 | this.action = EquipmentConfigurationMessage.ResponseIDs.GetEquipmentConfiguration - 1; 115 | this.createBaseMessage(senderId); 116 | this.writeInt32LE(0); 117 | this.writeInt32LE(0); 118 | this.unit.write(this.toBuffer()); 119 | return this; 120 | } 121 | public sendSetEquipmentConfigurationMessageAsync(data: rawData, senderId?: number): EquipmentCommands { 122 | this.action = EquipmentConfigurationMessage.ResponseIDs.SetEquipmentConfiguration; //setequipconfg 123 | this.createBaseMessage(senderId); 124 | this.writeInt32LE(0); 125 | this.writeInt32LE(0); 126 | this.unit.write(this.toBuffer()); 127 | return this; 128 | } 129 | public sendGetSystemTimeMessage(senderId?: number): EquipmentCommands { 130 | this.action = EquipmentStateMessage.ResponseIDs.SystemTime - 1; 131 | this.createBaseMessage(senderId); 132 | this.unit.write(this.toBuffer()); 133 | return this; 134 | } 135 | public sendCancelDelayMessage(senderId?: number): EquipmentCommands { 136 | this.action = EquipmentStateMessage.ResponseIDs.CancelDelay - 1; 137 | this.createBaseMessage(senderId); 138 | this.writeInt32LE(0); 139 | this.unit.write(this.toBuffer()); 140 | return this; 141 | } 142 | public sendGetCustomNamesMessage(senderId?: number): EquipmentCommands { 143 | this.action = EquipmentConfigurationMessage.ResponseIDs.GetCustomNamesAck - 1; 144 | this.createBaseMessage(senderId); 145 | this.writeInt32LE(0); 146 | this.unit.write(this.toBuffer()); 147 | return this; 148 | } 149 | public sendSetCustomNameMessage(idx: number, name: string, senderId?: number): EquipmentCommands { 150 | this.action = EquipmentConfigurationMessage.ResponseIDs.SetCustomNameAck - 1; 151 | this.createBaseMessage(senderId); 152 | this.writeInt32LE(this.controllerId); 153 | this.writeInt32LE(idx); 154 | this.writeSLString(name); 155 | this.unit.write(this.toBuffer()); 156 | return this; 157 | } 158 | public sendGetWeatherMessage(senderId?: number): EquipmentCommands { 159 | this.action = EquipmentConfigurationMessage.ResponseIDs.WeatherForecastAck - 1; 160 | this.createBaseMessage(senderId); 161 | this.writeInt32LE(0); 162 | this.writeInt32LE(0); 163 | this.unit.write(this.toBuffer()); 164 | return this; 165 | } 166 | public sendSetSystemTimeMessage(date: Date, shouldAdjustForDST: boolean, senderId?: number): EquipmentCommands { 167 | this.action = EquipmentStateMessage.ResponseIDs.SetSystemTime - 1; 168 | this.createBaseMessage(senderId); 169 | this.writeSLDateTime(date); 170 | this.writeInt32LE(shouldAdjustForDST ? 1 : 0); 171 | this.unit.write(this.toBuffer()); 172 | return this; 173 | } 174 | public sendGetHistoryMessage(fromTime: Date, toTime: Date, senderId?: number): EquipmentCommands { 175 | this.action = EquipmentConfigurationMessage.ResponseIDs.HistoryDataPending - 1; 176 | this.createBaseMessage(senderId); 177 | this.writeInt32LE(this.controllerId); 178 | this.writeSLDateTime(fromTime); 179 | this.writeSLDateTime(toTime); 180 | this.writeInt32LE(senderId ?? this.senderId); 181 | this.unit.write(this.toBuffer()); 182 | return this; 183 | } 184 | } 185 | 186 | export class CircuitCommands extends Commands { 187 | public sendSetCircuitMessage(circuitId: number, nameIndex: number, circuitFunction: number, circuitInterface: number, freeze: boolean, colorPos: number, senderId?: number): CircuitCommands { 188 | this.action = CircuitMessage.ResponseIDs.SetCircuitInfo - 1; 189 | this.createBaseMessage(senderId); 190 | this.writeInt32LE(this.controllerId); 191 | this.writeInt32LE(circuitId + 499); 192 | // normalize to 1 based ids for default names; 100 based for custom names 193 | // circuitArray[i].nameIndex = circuitArray[i].nameIndex < 101 ? circuitArray[i].nameIndex + 1 : circuitArray[i].nameIndex + 99; 194 | this.writeInt32LE(nameIndex < 102 ? nameIndex - 1 : nameIndex - 99); 195 | this.writeInt32LE(circuitFunction); 196 | this.writeInt32LE(circuitInterface); 197 | this.writeInt32LE(freeze ? 1 : 0); // could be other bits; this is a flag 198 | this.writeInt32LE(colorPos); 199 | this.encode(); 200 | this.unit.write(this.toBuffer()); 201 | return this; 202 | } 203 | public sendSetCircuitStateMessage(circuitId: number, circuitState: boolean, senderId?: number): CircuitCommands { 204 | this.action = CircuitMessage.ResponseIDs.SetCircuitState - 1; 205 | this.createBaseMessage(senderId); 206 | // this.addHeader(this.senderId, this.messageId); 207 | // this._controllerId = controllerId; 208 | this.writeInt32LE(this.controllerId); 209 | this.writeInt32LE(circuitId + 499); 210 | this.writeInt32LE((circuitState ? 1 : 0) || 0); 211 | this.encode(); 212 | this.unit.write(this.toBuffer()); 213 | return this; 214 | } 215 | public sendIntellibriteMessage(command: LightCommands, senderId?: number): CircuitCommands { 216 | this.action = CircuitMessage.ResponseIDs.SetLightState - 1; 217 | this.createBaseMessage(senderId); 218 | this.writeInt32LE(this.unit.controllerId); 219 | this.writeInt32LE(command || 0); 220 | this.unit.write(this.toBuffer()); 221 | return this; 222 | } 223 | public sendSetCircuitRuntimeMessage(circuitId: number, runTime: number, senderId?: number): CircuitCommands { 224 | this.action = CircuitMessage.ResponseIDs.SetCircuitRunTime - 1; 225 | this.createBaseMessage(senderId); 226 | this.writeInt32LE(this.unit.controllerId); 227 | this.writeInt32LE(circuitId + 499); 228 | this.writeInt32LE(runTime); 229 | this.unit.write(this.toBuffer()); 230 | return this; 231 | } 232 | } 233 | export class ChlorCommands extends Commands { 234 | public sendSetChlorOutputMessage(poolOutput: number, spaOutput: number, senderId?: number): ChlorCommands { 235 | this.action = ChlorMessage.ResponseIDs.SetIntellichlorConfig - 1; 236 | this.createBaseMessage(senderId); 237 | this.writeInt32LE(this.unit.controllerId); 238 | this.writeInt32LE(poolOutput || 0); 239 | this.writeInt32LE(spaOutput || 0); 240 | this.writeInt32LE(0); 241 | this.writeInt32LE(0); 242 | this.unit.write(this.toBuffer()); 243 | return this; 244 | } 245 | public sendGetSaltCellConfigMessage(senderId?: number): ChlorCommands { 246 | this.action = ChlorMessage.ResponseIDs.GetIntellichlorConfig - 1; 247 | this.createBaseMessage(senderId); 248 | this.writeInt32LE(this.unit.controllerId); 249 | this.unit.write(this.toBuffer()); 250 | return this; 251 | } 252 | public sendSetSaltCellEnableMessage(isActive?: boolean, senderId?: number): ChlorCommands { 253 | this.action = ChlorMessage.ResponseIDs.SetIntellichlorEnabled - 1; 254 | this.createBaseMessage(senderId); 255 | this.writeInt32LE(this.unit.controllerId); 256 | this.writeInt32LE(isActive ? 1 : 0); 257 | this.unit.write(this.toBuffer()); 258 | return this; 259 | } 260 | } 261 | export class ChemCommands extends Commands { 262 | public sendGetChemStatusMessage(senderId?: number): ChemCommands { 263 | this.action = ChemMessage.ResponseIDs.GetChemicalData - 1; 264 | this.createBaseMessage(senderId); 265 | this.writeInt32LE(0); 266 | this.unit.write(this.toBuffer()); 267 | return this; 268 | } 269 | public sendGetChemHistoryMessage(fromTime: Date, toTime: Date, senderId?: number): ChemCommands { 270 | this.action = ChemMessage.ResponseIDs.HistoryDataPending - 1; 271 | this.createBaseMessage(senderId); 272 | this.writeInt32LE(0); 273 | this.writeSLDateTime(fromTime); 274 | this.writeSLDateTime(toTime); 275 | this.writeInt32LE(senderId ?? this.senderId); 276 | this.unit.write(this.toBuffer()); 277 | return this; 278 | } 279 | } 280 | export class BodyCommands extends Commands { 281 | public sendSetPointMessage(bodyType: number, temperature: number, senderId?: number): BodyCommands { 282 | this.action = HeaterMessage.ResponseIDs.SetHeatSetPoint - 1; 283 | this.createBaseMessage(senderId); 284 | this.writeInt32LE(this.unit.controllerId); 285 | this.writeInt32LE(bodyType || 0); 286 | this.writeInt32LE(temperature || 0); 287 | this.unit.write(this.toBuffer()); 288 | return this; 289 | } 290 | public sendCoolSetPointMessage(bodyType: number, temperature: number, senderId?: number): BodyCommands { 291 | this.action = HeaterMessage.ResponseIDs.SetCoolSetPoint - 1; 292 | this.createBaseMessage(senderId); 293 | this.writeInt32LE(this.unit.controllerId); 294 | this.writeInt32LE(bodyType || 0); 295 | this.writeInt32LE(temperature || 0); 296 | this.unit.write(this.toBuffer()); 297 | return this; 298 | } 299 | public sendHeatModeMessage(bodyType: number, heatMode: number, senderId?: number): BodyCommands { 300 | this.action = HeaterMessage.ResponseIDs.SetHeatMode - 1; 301 | this.createBaseMessage(senderId); 302 | this.writeInt32LE(this.unit.controllerId); 303 | this.writeInt32LE(bodyType || 0); 304 | this.writeInt32LE(heatMode || 0); 305 | this.unit.write(this.toBuffer()); 306 | return this; 307 | } 308 | } 309 | export class ScheduleCommands extends Commands { 310 | public sendGetSchedulesMessage(schedType: number, senderId?: number): ScheduleCommands { 311 | this.action = ScheduleMessage.ResponseIDs.GetSchedule - 1; 312 | this.createBaseMessage(senderId); 313 | this.writeInt32LE(0); 314 | this.writeInt32LE(schedType); 315 | this.unit.write(this.toBuffer()); 316 | return this; 317 | } 318 | public sendAddScheduleEventMessage(schedType: number, senderId?: number): ScheduleCommands { 319 | this.action = ScheduleMessage.ResponseIDs.AddSchedule - 1; 320 | this.createBaseMessage(senderId); 321 | this.writeInt32LE(0); 322 | this.writeInt32LE(schedType); 323 | this.unit.write(this.toBuffer()); 324 | return this; 325 | } 326 | public sendDeleteScheduleEventMessage(schedId: number, senderId?: number): ScheduleCommands { 327 | this.action = ScheduleMessage.ResponseIDs.DeleteSchedule - 1; 328 | this.createBaseMessage(senderId); 329 | this.writeInt32LE(this.controllerId); 330 | this.writeInt32LE(schedId + 699); 331 | this.unit.write(this.toBuffer()); 332 | return this; 333 | } 334 | public sendSetScheduleEventMessage(scheduleId: number, circuitId: number, startTime: number, stopTime: number, dayMask: number, flags: number, heatCmd: number, heatSetPoint: number, senderId?: number): ScheduleCommands { 335 | this.action = ScheduleMessage.ResponseIDs.SetSchedule - 1; 336 | this.createBaseMessage(senderId); 337 | this.writeInt32LE(0); 338 | this.writeInt32LE(scheduleId + 699); 339 | this.writeInt32LE(circuitId + 499); 340 | this.writeInt32LE(startTime); 341 | this.writeInt32LE(stopTime); 342 | this.writeInt32LE(dayMask); 343 | this.writeInt32LE(flags); 344 | this.writeInt32LE(heatCmd); 345 | this.writeInt32LE(heatSetPoint); 346 | this.unit.write(this.toBuffer()); 347 | return this; 348 | } 349 | } 350 | export class PumpCommands extends Commands { 351 | public sendGetPumpStatusMessage(pumpId: number, senderId?: number): PumpCommands { 352 | this.action = PumpMessage.ResponseIDs.PumpStatus - 1; 353 | this.createBaseMessage(senderId); 354 | this.writeInt32LE(this.controllerId); 355 | this.writeInt32LE(pumpId - 1); 356 | this.unit.write(this.toBuffer()); 357 | return this; 358 | } 359 | public sendSetPumpSpeed(pumpId: number, circuitId: number, speed: number, isRPMs?: boolean, senderId?: number): PumpCommands { 360 | this.action = PumpMessage.ResponseIDs.SetPumpSpeed - 1; 361 | if (typeof isRPMs === 'undefined') { 362 | if (speed < 400) { isRPMs = false; } 363 | else isRPMs = true; 364 | } 365 | const _isRPMs = isRPMs ? 1 : 0; 366 | this.createBaseMessage(senderId); 367 | this.writeInt32LE(this.controllerId); 368 | this.writeInt32LE(pumpId - 1); 369 | this.writeInt32LE(circuitId); // This is indexed to the array of circuits returned in GetPumpStatus 370 | this.writeInt32LE(speed); 371 | this.writeInt32LE(_isRPMs); 372 | this.unit.write(this.toBuffer()); 373 | return this; 374 | } 375 | } 376 | export class OutboundGateway extends Outbound { 377 | public createSendGatewayMessage(systemName: string, senderId?: number): Buffer { 378 | this.action = ConnectionMessage.ResponseIDs.GatewayResponse - 1; 379 | this.createBaseMessage(senderId); 380 | this.writeSLString(systemName); 381 | this.writeSLString(systemName); 382 | return this.toBuffer(); 383 | } 384 | } -------------------------------------------------------------------------------- /messages/SLGatewayDataMessage.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { Inbound } from './SLMessage'; 4 | 5 | export class SLReceiveGatewayDataMessage extends Inbound { 6 | // static MSG_ID = _MSG_ID; 7 | private data: SLGateWayData; 8 | constructor(buf: Buffer) { 9 | super(0, 0); 10 | this.readFromBuffer(buf); 11 | this.decode(); 12 | } 13 | 14 | 15 | decode() { 16 | super.decode(); 17 | 18 | const gatewayFound = this._smartBuffer.readUInt8() !== 0; 19 | const licenseOK = this._smartBuffer.readUInt8() !== 0; 20 | const ipAddr = this.readSLString(); 21 | const port = this._smartBuffer.readUInt16LE(); 22 | const portOpen = this._smartBuffer.readUInt8() !== 0; 23 | const relayOn = this._smartBuffer.readUInt8() !== 0; 24 | this.data = { 25 | gatewayFound, 26 | licenseOK, 27 | ipAddr, 28 | port, 29 | portOpen, 30 | relayOn 31 | }; 32 | 33 | } 34 | get(): SLGateWayData { 35 | return this.data; 36 | } 37 | } 38 | 39 | 40 | // export class SLSendGatewayDataMessage extends Outbound { 41 | // // static MSG_ID = _MSG_ID; 42 | // constructor(systemName: string) { 43 | // super(0, 0); 44 | // this.systemName = systemName; 45 | // this.writeMessage(); 46 | // } 47 | // private systemName: string; 48 | 49 | // public writeMessage(): void { 50 | 51 | // this.messageId = 18003; // SLSendGatewayDataMessage.MSG_ID; 52 | // this.createBaseMessage(); 53 | // this.writeSLString(this.systemName); 54 | // this.writeSLString(this.systemName); 55 | // } 56 | // }; 57 | 58 | export interface SLGateWayData { 59 | gatewayFound: boolean, 60 | licenseOK: boolean, 61 | ipAddr: string, 62 | port: number, 63 | portOpen: boolean, 64 | relayOn: boolean 65 | } -------------------------------------------------------------------------------- /messages/SLMessage.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { SmartBuffer } from 'smart-buffer'; 4 | 5 | interface Map { 6 | [key: string]: number 7 | } 8 | 9 | const DAY_VALUES: Map = { 10 | Mon: 0x1, 11 | Tue: 0x2, 12 | Wed: 0x4, 13 | Thu: 0x8, 14 | Fri: 0x10, 15 | Sat: 0x20, 16 | Sun: 0x40, 17 | }; 18 | 19 | 20 | export interface SLData { 21 | senderId: number; 22 | } 23 | 24 | 25 | export interface SLSimpleBoolData extends SLData { 26 | val: boolean 27 | } 28 | 29 | 30 | export interface SLSimpleNumberData extends SLData { 31 | val: number 32 | } 33 | 34 | 35 | export class SLMessage { 36 | static MSG_ID: number; 37 | constructor(controllerId?: number, senderId?: number) { 38 | this.controllerId = controllerId ?? 0; 39 | this.senderId = senderId ?? 0; 40 | } 41 | protected _wroteSize: boolean; 42 | public action: number; 43 | public senderId = 0; 44 | public controllerId = 0; 45 | protected dataLength: number; 46 | protected _smartBuffer: SmartBuffer; 47 | public get readOffset() { return this._smartBuffer.readOffset; } 48 | public get length() { return this._smartBuffer.length; } 49 | public static slackForAlignment(val: number) { 50 | return (4 - val % 4) % 4; 51 | } 52 | public getDayValue(dayName: string): number { 53 | if (!(dayName in DAY_VALUES)) { 54 | return 0; 55 | } 56 | return DAY_VALUES[dayName]; 57 | } 58 | public toBuffer() { 59 | return this._smartBuffer.toBuffer(); 60 | } 61 | } 62 | 63 | export class Inbound extends SLMessage { 64 | public readFromBuffer(buf: Buffer) { 65 | this._smartBuffer = SmartBuffer.fromBuffer(buf); 66 | this.decode(); 67 | } 68 | public readMessage(buf: Buffer) { 69 | this._wroteSize = true; 70 | this._smartBuffer.writeBuffer(buf, 0); 71 | 72 | this.decode(); 73 | } 74 | public readSLString() { 75 | const len = this._smartBuffer.readInt32LE(); 76 | const str = this._smartBuffer.readString(len); 77 | this._smartBuffer.readOffset += SLMessage.slackForAlignment(len); 78 | return str; 79 | } 80 | readSLArray(): Array { 81 | const len = this._smartBuffer.readInt32LE(); 82 | 83 | const retval = new Array(len); 84 | for (let i = 0; i < len; i++) { 85 | retval[i] = this._smartBuffer.readUInt8(); 86 | } 87 | 88 | this._smartBuffer.readOffset += SLMessage.slackForAlignment(len); 89 | 90 | return retval; 91 | } 92 | decode() { 93 | this._smartBuffer.readOffset = 0; 94 | this.senderId = this._smartBuffer.readUInt16LE(); 95 | this.action = this._smartBuffer.readUInt16LE(); 96 | this.dataLength = this._smartBuffer.readInt32LE(); 97 | } 98 | isBitSet(value: number, bit: number): boolean { 99 | return ((value >> bit) & 0x1) === 1; 100 | } 101 | decodeTime(rawTime: number) { // Takes 'rawTime' in mins past midnight and returns military time as a string 102 | let retVal; 103 | 104 | retVal = Math.floor(rawTime / 60) * 100 + rawTime % 60; 105 | 106 | retVal = String(retVal).padStart(4, '0'); 107 | 108 | return retVal; 109 | } 110 | decodeDayMask(dayMask: number): string[] { 111 | const days = []; 112 | 113 | for (let i = 0; i < 7; i++) { 114 | if (this.isBitSet(dayMask, i)) { 115 | days.push(Object.keys(DAY_VALUES)[i]); 116 | } 117 | } 118 | return days; 119 | } 120 | 121 | readSLDateTime() { 122 | const year = this._smartBuffer.readInt16LE(); 123 | const month = this._smartBuffer.readInt16LE() - 1; 124 | this._smartBuffer.readInt16LE(); // day of week 125 | const day = this._smartBuffer.readInt16LE(); 126 | const hour = this._smartBuffer.readInt16LE(); 127 | const minute = this._smartBuffer.readInt16LE(); 128 | const second = this._smartBuffer.readInt16LE(); 129 | const millisecond = this._smartBuffer.readInt16LE(); 130 | 131 | const date = new Date(year, month, day, hour, minute, second, millisecond); 132 | return date; 133 | } 134 | readUInt8() { 135 | return this._smartBuffer.readUInt8(); 136 | } 137 | readUInt16BE() { 138 | return this._smartBuffer.readUInt16BE(); 139 | } 140 | readUInt16LE() { 141 | return this._smartBuffer.readUInt16LE(); 142 | } 143 | readInt32LE() { 144 | return this._smartBuffer.readInt32LE(); 145 | } 146 | readUInt32LE() { 147 | return this._smartBuffer.readUInt32LE(); 148 | } 149 | incrementReadOffset(val: number) { 150 | this._smartBuffer.readOffset = this._smartBuffer.readOffset + val; 151 | } 152 | toString() { 153 | return this._smartBuffer.toString(); 154 | } 155 | toHexStream() { 156 | return this._smartBuffer.toString('hex'); 157 | } 158 | } 159 | 160 | 161 | export class Outbound extends SLMessage { 162 | constructor(controllerId?: number, senderId?: number, messageId?: number) { 163 | super(controllerId, senderId); 164 | 165 | this.action = messageId; 166 | } 167 | public createBaseMessage(senderId?: number) { 168 | this._smartBuffer = new SmartBuffer(); 169 | this.addHeader(senderId); 170 | } 171 | public addHeader(senderId?: number) { 172 | 173 | this._smartBuffer.writeUInt16LE(senderId ?? this.senderId); 174 | this._smartBuffer.writeUInt16LE(this.action); 175 | 176 | this._wroteSize = false; 177 | } 178 | 179 | encodeDayMask(daysArray: string[]) { 180 | let dayMask = 0; 181 | 182 | for (let i = 0; i < daysArray.length; i++) { 183 | dayMask += this.getDayValue(daysArray[i]); 184 | } 185 | return dayMask; 186 | } 187 | writeSLDateTime(date: Date) { 188 | this._smartBuffer.writeInt16LE(date.getFullYear()); 189 | this._smartBuffer.writeInt16LE(date.getMonth() + 1); 190 | this._smartBuffer.writeInt16LE(date.getDay() + 1); 191 | this._smartBuffer.writeInt16LE(date.getDate()); 192 | this._smartBuffer.writeInt16LE(date.getHours()); 193 | this._smartBuffer.writeInt16LE(date.getMinutes()); 194 | this._smartBuffer.writeInt16LE(date.getSeconds()); 195 | this._smartBuffer.writeInt16LE(date.getMilliseconds()); 196 | } 197 | writeInt32LE(val: number) { 198 | this._smartBuffer.writeInt32LE(val); 199 | } 200 | encode() { null; } 201 | static getResponseId() { 202 | return this.MSG_ID + 1; 203 | } 204 | public toBuffer() { 205 | this.encode(); 206 | 207 | if (this._wroteSize === false) { 208 | this._smartBuffer.insertInt32LE(this._smartBuffer.length - 4, 4); 209 | this._wroteSize = true; 210 | } else { 211 | this._smartBuffer.writeInt32LE(this._smartBuffer.length - 8, 4); 212 | } 213 | 214 | return this._smartBuffer.toBuffer(); 215 | } 216 | writeSLString(str: string) { 217 | this._smartBuffer.writeInt32LE(str.length); 218 | this._smartBuffer.writeString(str); 219 | this.skipWrite(SLMessage.slackForAlignment(str.length)); 220 | } 221 | writeSLBuffer(buf: Buffer) { 222 | this._smartBuffer.writeInt32LE(buf.length); 223 | this._smartBuffer.writeBuffer(buf); 224 | } 225 | writeSLArray(arr: Buffer) { 226 | this._smartBuffer.writeInt32LE(arr.length); 227 | 228 | for (let i = 0; i < arr.length; i++) { 229 | this._smartBuffer.writeUInt8(arr[i]); 230 | } 231 | 232 | this.skipWrite(SLMessage.slackForAlignment(arr.length)); 233 | } 234 | skipWrite(num: number) { 235 | if (num > 0) { 236 | this._smartBuffer.writeBuffer(Buffer.alloc(num)); 237 | } 238 | } 239 | encodeTime(stringTime: string) { // Takes 'stringTime' as military time and returns mins past midnight 240 | return (Number(stringTime.substring(0, 2)) * 60) + Number(stringTime.substring(2, 4)); 241 | } 242 | } 243 | -------------------------------------------------------------------------------- /messages/config/CircuitMessage.ts: -------------------------------------------------------------------------------- 1 | import { Inbound, SLSimpleBoolData } from '../SLMessage'; 2 | 3 | 4 | export class CircuitMessage { 5 | public static decodeSetCircuit(msg: Inbound): SLSimpleBoolData { 6 | const response: SLSimpleBoolData = { 7 | senderId: msg.senderId, 8 | val: true 9 | }; 10 | return response; 11 | } 12 | 13 | public static decodeSetCircuitState(msg: Inbound): SLSimpleBoolData { 14 | // ack 15 | const response: SLSimpleBoolData = { 16 | senderId: msg.senderId, 17 | val: true 18 | }; 19 | return response; 20 | } 21 | public static decodeSetLight(msg: Inbound): SLSimpleBoolData { 22 | // ack 23 | const response: SLSimpleBoolData = { 24 | senderId: msg.senderId, 25 | val: true 26 | }; 27 | return response; 28 | } 29 | public static decodeSetCircuitRunTime(msg: Inbound): SLSimpleBoolData { 30 | // ack 31 | const response: SLSimpleBoolData = { 32 | senderId: msg.senderId, 33 | val: true 34 | }; 35 | return response; 36 | } 37 | } 38 | 39 | export namespace CircuitMessage { // eslint-disable-line @typescript-eslint/no-namespace 40 | export enum ResponseIDs { 41 | LightSequence = 12504, 42 | SetCircuitInfo = 12521, 43 | SetCircuitState = 12531, 44 | SetCircuitRunTime = 12551, 45 | SetLightState = 12557, 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /messages/config/HeaterMessage.ts: -------------------------------------------------------------------------------- 1 | import { Inbound, SLSimpleBoolData } from '../SLMessage'; 2 | 3 | export class HeaterMessage { 4 | public static decodeSetHeatSetPoint(msg: Inbound): SLSimpleBoolData { 5 | // ack 6 | const response: SLSimpleBoolData = { 7 | senderId: msg.senderId, 8 | val: true 9 | }; 10 | return response; 11 | } 12 | public static decodeCoolSetHeatSetPoint(msg: Inbound): SLSimpleBoolData { 13 | // ack 14 | const response: SLSimpleBoolData = { 15 | senderId: msg.senderId, 16 | val: true 17 | }; 18 | return response; 19 | } 20 | public static decodeSetHeatModePoint(msg: Inbound): SLSimpleBoolData { 21 | // ack 22 | const response: SLSimpleBoolData = { 23 | senderId: msg.senderId, 24 | val: true 25 | }; 26 | return response; 27 | } 28 | } 29 | 30 | export namespace HeaterMessage { // eslint-disable-line @typescript-eslint/no-namespace 31 | export enum ResponseIDs { 32 | SetHeatSetPoint = 12529, 33 | SetHeatMode = 12539, 34 | SetCoolSetPoint = 12591, 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /messages/config/ScheduleMessage.ts: -------------------------------------------------------------------------------- 1 | import { Inbound, SLData, SLSimpleBoolData, SLSimpleNumberData } from '../SLMessage'; 2 | 3 | 4 | export class ScheduleMessage { 5 | public static decodeGetScheduleMessage(msg: Inbound): SLScheduleData { 6 | const eventCount = msg.readUInt32LE(); 7 | const data: SLScheduleDatum[] = []; 8 | for (let i = 0; i < eventCount; i++) { 9 | const scheduleId = msg.readUInt32LE() - 699; 10 | const circuitId = msg.readUInt32LE() - 499; 11 | const startTime = msg.decodeTime(msg.readUInt32LE()); 12 | const stopTime = msg.decodeTime(msg.readUInt32LE()); 13 | const dayMask = msg.readUInt32LE(); 14 | const flags = msg.readUInt32LE(); 15 | const heatCmd = msg.readUInt32LE(); 16 | const heatSetPoint = msg.readUInt32LE(); 17 | const days = msg.decodeDayMask(dayMask); 18 | const event: SLScheduleDatum = { 19 | scheduleId, 20 | circuitId, 21 | startTime, 22 | stopTime, 23 | dayMask, 24 | flags, 25 | heatCmd, 26 | heatSetPoint, 27 | days 28 | }; 29 | data.push(event); 30 | } 31 | const result: SLScheduleData = { 32 | senderId: msg.senderId, 33 | data 34 | }; 35 | return result; 36 | } 37 | public static decodeAddSchedule(msg: Inbound): SLSimpleNumberData { 38 | const response: SLSimpleNumberData = { 39 | senderId: msg.senderId, 40 | val: msg.readUInt32LE() - 699 41 | }; 42 | return response; 43 | } 44 | public static decodeDeleteSchedule(msg: Inbound): SLSimpleBoolData { 45 | // ack 46 | const response: SLSimpleBoolData = { 47 | senderId: msg.senderId, 48 | val: true 49 | }; 50 | return response; 51 | } 52 | public static decodeSetSchedule(msg: Inbound): SLSimpleBoolData { 53 | // ack 54 | const response: SLSimpleBoolData = { 55 | senderId: msg.senderId, 56 | val: true 57 | }; 58 | return response; 59 | } 60 | } 61 | 62 | export namespace ScheduleMessage { // eslint-disable-line @typescript-eslint/no-namespace 63 | export enum ResponseIDs { 64 | ScheduleChanged = 12501, 65 | GetSchedule = 12543, 66 | AddSchedule = 12545, 67 | DeleteSchedule = 12547, 68 | SetSchedule = 12549, 69 | } 70 | } 71 | 72 | export interface SLScheduleDatum { 73 | scheduleId: number; 74 | circuitId: number; 75 | startTime: string; 76 | stopTime: string; 77 | dayMask: number; 78 | flags: number; 79 | heatCmd: number; 80 | heatSetPoint: number; 81 | days: string[]; 82 | } 83 | 84 | export interface SLScheduleData extends SLData { 85 | data: SLScheduleDatum[] 86 | } 87 | -------------------------------------------------------------------------------- /messages/state/ChemMessage.ts: -------------------------------------------------------------------------------- 1 | import { Inbound, SLData } from '../SLMessage'; 2 | 3 | 4 | export class ChemMessage { 5 | public static decodeChemDataMessage(msg: Inbound) { 6 | let isValid = false; 7 | 8 | const sentinel = msg.readInt32LE(); 9 | if (sentinel === 42) { 10 | isValid = true; 11 | // msg._smartBuffer.readOffset++; 12 | msg.incrementReadOffset(1); 13 | const pH = msg.readUInt16BE() / 100; 14 | const orp = msg.readUInt16BE(); 15 | const pHSetPoint = msg.readUInt16BE() / 100; 16 | const orpSetPoint = msg.readUInt16BE(); 17 | // msg._smartBuffer.readOffset += 12; 18 | msg.incrementReadOffset(12); 19 | const pHTankLevel = msg.readUInt8(); 20 | const orpTankLevel = msg.readUInt8(); 21 | let saturation = msg.readUInt8(); 22 | if ((saturation & 128) !== 0) { 23 | saturation = -(256 - saturation); 24 | } 25 | saturation /= 100; 26 | const calcium = msg.readUInt16BE(); 27 | const cyanuricAcid = msg.readUInt16BE(); 28 | const alkalinity = msg.readUInt16BE(); 29 | const salt = msg.readUInt16LE(); 30 | const saltPPM = salt * 50; 31 | const temperature = msg.readUInt8(); 32 | msg.incrementReadOffset(2); 33 | const balance = msg.readUInt8(); 34 | const corrosive = (balance & 1) !== 0; 35 | const scaling = (balance & 2) !== 0; 36 | const error = (salt & 128) !== 0; 37 | const data: SLChemData = { 38 | senderId: msg.senderId, 39 | isValid, 40 | pH, 41 | orp, 42 | pHSetPoint, 43 | orpSetPoint, 44 | pHTankLevel, 45 | orpTankLevel, 46 | saturation, 47 | calcium, 48 | cyanuricAcid, 49 | alkalinity, 50 | saltPPM, 51 | temperature, 52 | balance, 53 | corrosive, 54 | scaling, 55 | error 56 | }; 57 | return data; 58 | } 59 | } 60 | public static decodecChemHistoryMessage(msg: Inbound) { 61 | const readTimePHPointsPairs = () => { 62 | const retval:TimePHPointsPairs[] = []; 63 | // 4 bytes for the length 64 | if (msg.length >= msg.readOffset + 4) { 65 | const points = msg.readInt32LE(); 66 | // 16 bytes per time, 4 bytes per pH reading 67 | if (msg.length >= msg.readOffset + (points * (16 + 4))) { 68 | for (let i = 0; i < points; i++) { 69 | const time = msg.readSLDateTime(); 70 | const pH = msg.readInt32LE() / 100; 71 | retval.push({ 72 | time: time, 73 | pH: pH, 74 | }); 75 | } 76 | } 77 | } 78 | 79 | return retval; 80 | }; 81 | 82 | const readTimeORPPointsPairs = () => { 83 | const retval: TimeORPPointsPairs[] = []; 84 | // 4 bytes for the length 85 | if (msg.length >= msg.readOffset + 4) { 86 | const points = msg.readInt32LE(); 87 | // 16 bytes per time, 4 bytes per ORP reading 88 | if (msg.length >= msg.readOffset + (points * (16 + 4))) { 89 | for (let i = 0; i < points; i++) { 90 | const time = msg.readSLDateTime(); 91 | const orp = msg.readInt32LE(); 92 | retval.push({ 93 | time: time, 94 | orp: orp, 95 | }); 96 | } 97 | } 98 | } 99 | 100 | return retval; 101 | }; 102 | 103 | const readTimeTimePointsPairs = () => { 104 | const retval:TimeTimePointsPairs[] = []; 105 | // 4 bytes for the length 106 | if (msg.length >= msg.readOffset + 4) { 107 | const points = msg.readInt32LE(); 108 | // 16 bytes per on time, 16 bytes per off time 109 | if (msg.length >= msg.readOffset + (points * (16 + 16))) { 110 | for (let i = 0; i < points; i++) { 111 | const onTime = msg.readSLDateTime(); 112 | const offTime = msg.readSLDateTime(); 113 | retval.push({ 114 | on: onTime, 115 | off: offTime, 116 | }); 117 | } 118 | } 119 | } 120 | 121 | return retval; 122 | }; 123 | const data: SLChemHistory = { 124 | phPoints: readTimePHPointsPairs(), 125 | orpPoints: readTimeORPPointsPairs(), 126 | phRuns: readTimeTimePointsPairs(), 127 | orpRuns: readTimeTimePointsPairs() 128 | }; 129 | return data; 130 | } 131 | } 132 | 133 | export namespace ChemMessage { // eslint-disable-line @typescript-eslint/no-namespace 134 | export enum ResponseIDs { 135 | AsyncChemicalData = 12505, 136 | ChemicalHistoryData = 12506, 137 | HistoryDataPending = 12597, 138 | GetChemicalData = 12593, 139 | } 140 | } 141 | 142 | export interface SLChemData extends SLData { 143 | isValid: boolean; 144 | pH: number; 145 | orp: number; 146 | pHSetPoint: number; 147 | orpSetPoint: number; 148 | pHTankLevel: number; 149 | orpTankLevel: number; 150 | saturation: number; 151 | calcium: number; 152 | cyanuricAcid: number; 153 | alkalinity: number; 154 | saltPPM: number; 155 | temperature: number; 156 | balance: number; 157 | corrosive: boolean; 158 | scaling: boolean; 159 | error: boolean; 160 | } 161 | 162 | export interface TimePHPointsPairs { 163 | time: Date; 164 | pH: number; 165 | } 166 | export interface TimeORPPointsPairs { 167 | time: Date; 168 | orp: number; 169 | } 170 | export interface TimeTimePointsPairs { 171 | on: Date; 172 | off: Date; 173 | } 174 | export interface SLChemHistory { 175 | phPoints: TimePHPointsPairs[]; 176 | orpPoints: TimeORPPointsPairs[]; 177 | phRuns: TimeTimePointsPairs[]; 178 | orpRuns: TimeTimePointsPairs[]; 179 | } 180 | -------------------------------------------------------------------------------- /messages/state/ChlorMessage.ts: -------------------------------------------------------------------------------- 1 | import { Inbound, SLData, SLSimpleBoolData } from '../SLMessage'; 2 | 3 | 4 | export class ChlorMessage { 5 | public static decodeIntellichlorConfig(msg: Inbound){ 6 | const data: SLIntellichlorData = { 7 | senderId: msg.senderId, 8 | installed: msg.readInt32LE() === 1, 9 | status: msg.readInt32LE(), 10 | poolSetPoint: msg.readInt32LE(), 11 | spaSetPoint: msg.readInt32LE(), 12 | salt: msg.readInt32LE() * 50, 13 | flags: msg.readInt32LE(), 14 | superChlorTimer: msg.readInt32LE() 15 | }; 16 | return data; 17 | } 18 | public static decodeSetIntellichlorConfig(msg: Inbound): SLSimpleBoolData { 19 | // ack 20 | const response: SLSimpleBoolData = { 21 | senderId: msg.senderId, 22 | val: true 23 | }; 24 | return response; 25 | } 26 | public static decodeSetEnableIntellichlorConfig(msg: Inbound): SLSimpleBoolData { 27 | // ack 28 | const response: SLSimpleBoolData = { 29 | senderId: msg.senderId, 30 | val: true 31 | }; 32 | return response; 33 | } 34 | } 35 | 36 | export namespace ChlorMessage { // eslint-disable-line @typescript-eslint/no-namespace 37 | export enum ResponseIDs { 38 | GetIntellichlorConfig = 12573, 39 | SetIntellichlorEnabled = 12575, 40 | SetIntellichlorConfig = 12577, 41 | } 42 | } 43 | 44 | export interface SLIntellichlorData extends SLData { 45 | installed: boolean; 46 | status: number; 47 | poolSetPoint: number; 48 | spaSetPoint: number; 49 | salt: number; 50 | flags: number; 51 | superChlorTimer: number; 52 | } -------------------------------------------------------------------------------- /messages/state/PumpMessage.ts: -------------------------------------------------------------------------------- 1 | import { PumpTypes } from '../../index'; 2 | import { Inbound, SLData, SLSimpleBoolData } from '../SLMessage'; 3 | 4 | 5 | export class PumpMessage { 6 | public static decodePumpStatus(msg: Inbound){ 7 | // This pump type seems to be different: 8 | // 1 = VF 9 | // 2 = VS 10 | // 3 = VSF 11 | // The equipmentConfig message gives more specifics on the pump type 12 | const _pumpType = msg.readUInt32LE(); 13 | const pumpType = _pumpType === 1 ? PumpTypes.PUMP_TYPE_INTELLIFLOVF : _pumpType === 2 ? PumpTypes.PUMP_TYPE_INTELLIFLOVS : _pumpType === 3 ? PumpTypes.PUMP_TYPE_INTELLIFLOVSF : _pumpType; 14 | const isRunning = msg.readUInt32LE() !== 0; // 0, 1, or 4294967295 (FF FF FF FF) 15 | const pumpWatts = msg.readUInt32LE(); 16 | const pumpRPMs = msg.readUInt32LE(); 17 | const pumpUnknown1 = msg.readUInt32LE(); // Always 0 18 | const pumpGPMs = msg.readUInt32LE(); 19 | const pumpUnknown2 = msg.readUInt32LE(); // Always 255 20 | 21 | const pumpCircuits = []; 22 | for (let i = 0; i < 8; i++) { 23 | const _pumpCirc: SLPumpCircuitData = { 24 | circuitId: msg.readUInt32LE(), 25 | speed: msg.readUInt32LE(), 26 | isRPMs: msg.readUInt32LE() !== 0 // 1 for RPMs; 0 for GPMs 27 | }; 28 | pumpCircuits.push(_pumpCirc); 29 | } 30 | const data: SLPumpStatusData = { 31 | senderId: msg.senderId, 32 | pumpCircuits, 33 | pumpType, 34 | isRunning, 35 | pumpWatts, 36 | pumpRPMs, 37 | pumpUnknown1, 38 | pumpGPMs, 39 | pumpUnknown2 40 | }; 41 | return data; 42 | } 43 | public static decodeSetPumpSpeed(msg:Inbound): SLSimpleBoolData { 44 | // ack 45 | const response: SLSimpleBoolData = { 46 | senderId: msg.senderId, 47 | val: true 48 | }; 49 | return response; 50 | } 51 | } 52 | 53 | export namespace PumpMessage { // eslint-disable-line @typescript-eslint/no-namespace 54 | export enum ResponseIDs { 55 | PumpStatus = 12585, 56 | SetPumpSpeed = 12587, 57 | } 58 | } 59 | 60 | export interface SLPumpStatusData extends SLData { 61 | pumpCircuits: SLPumpCircuitData[]; 62 | pumpType: PumpTypes; 63 | isRunning: boolean; 64 | pumpWatts: number; 65 | pumpRPMs: number; 66 | pumpUnknown1: number; 67 | pumpGPMs: number; 68 | pumpUnknown2: number; 69 | } 70 | 71 | export interface SLPumpCircuitData { 72 | circuitId: number; 73 | speed: number; 74 | isRPMs: boolean; 75 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-screenlogic", 3 | "description": "Tool for connecting to Pentair ScreenLogic systems on the local network", 4 | "version": "2.1.1", 5 | "main": "./dist/index.js", 6 | "types": "./dist/index.d.ts", 7 | "license": "MIT", 8 | "repository": "https://github.com/parnic/node-screenlogic.git", 9 | "keywords": [ 10 | "pentair", 11 | "pool", 12 | "screenlogic", 13 | "swimmingpool" 14 | ], 15 | "dependencies": { 16 | "debug": "^4.3.2", 17 | "smart-buffer": "^4.2.0", 18 | "source-map-support": "^0.5.21" 19 | }, 20 | "devDependencies": { 21 | "@types/debug": "^4.1.7", 22 | "@types/node": "^16.18.0", 23 | "@typescript-eslint/eslint-plugin": "^5.53.0", 24 | "@typescript-eslint/parser": "^5.53.0", 25 | "eslint": "^8.34.0", 26 | "eslint-config-strongloop": "^2.1.0", 27 | "mocha": "^11.1.0", 28 | "typescript": "^4.9.5" 29 | }, 30 | "scripts": { 31 | "test": "mocha test/*.spec.js", 32 | "pretest": "eslint . ", 33 | "test-slmessage": "mocha test/slmessage.spec.js", 34 | "test-passwordencoder": "mocha test/password.spec.js", 35 | "build": "tsc", 36 | "lint": "eslint --fix --ext .js,.jsx,.ts ." 37 | }, 38 | "engines": { 39 | "npm": ">=6.0.0", 40 | "node": ">=14.0.0" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /test/find.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const ScreenLogic = require('../dist/index'); 4 | 5 | // you'll need a ScreenLogic-enabled device on your network for this to succeed 6 | describe('Finder', function() { 7 | it('finds a server', function(done) { 8 | let finder = new ScreenLogic.FindUnits(); 9 | finder.on('serverFound', server => { 10 | finder.close(); 11 | done(); 12 | }); 13 | finder.search(); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /test/password.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const assert = require('assert'); 4 | const HLEncoder = require('../dist/utils/PasswordEncoder').HLEncoder; 5 | 6 | describe('Password encoder', function() { 7 | it('encodes correctly', function() { 8 | let pw = new HLEncoder('1234').getEncryptedPassword('00-00-00-00-00-00'); 9 | assert.equal(true, pw.equals(Buffer.from([0x4e, 0x71, 0x7f, 0x2e, 0xff, 0xda, 0xfd, 0x5d, 0xdf, 0x34, 0x26, 0x32, 0x23, 0xd7, 0x11, 0x06, 0x72, 0xbc, 0x40, 0x0f, 0x61, 0x81, 0x9f, 0xc8, 0x84, 0xcc, 0x6b, 0xaa, 0x0b, 0x16, 0x77, 0xab]))); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /test/slmessage.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const SLMessage = require('../dist/messages/SLMessage.js'); 4 | const assert = require('assert'); 5 | 6 | function slMessageLen(str) { 7 | // strings have length prefixed on them as an int32 for an additional 4b. 8 | // strings are dword aligned, so if str.length is 21, dword alignment pushes it up to 24 9 | return 4 + str.length + SLMessage.SLMessage.slackForAlignment(str.length); 10 | } 11 | 12 | describe('SLMessage utilities', function() { 13 | // message header = senderId, messageId, bodyLen. 14 | // senderId and messageId are int16's, so 2b each. bodyLen is an int32, so 4b. total 8b. 15 | let msgHeaderLen = 8; 16 | 17 | it('sets senderId and messageId properly', function() { 18 | { 19 | let msg = new SLMessage.Outbound(0, 123, 456); 20 | msg.createBaseMessage(); 21 | let decodedMsg = new SLMessage.Inbound(); 22 | decodedMsg.readFromBuffer(msg.toBuffer()); 23 | assert.strictEqual(decodedMsg.senderId, 123); 24 | assert.strictEqual(decodedMsg.action, 456); 25 | assert.strictEqual(decodedMsg.dataLength, 0); 26 | } 27 | 28 | { 29 | let msg = new SLMessage.Outbound(0, 0, 65534); 30 | msg.createBaseMessage(); 31 | let decodedMsg = new SLMessage.Inbound(); 32 | decodedMsg.readFromBuffer(msg.toBuffer()); 33 | assert.strictEqual(decodedMsg.senderId, 0); 34 | assert.strictEqual(decodedMsg.action, 65534); 35 | assert.strictEqual(decodedMsg.dataLength, 0); 36 | } 37 | 38 | { 39 | let msg = new SLMessage.Outbound(); 40 | msg.createBaseMessage(); 41 | let decodedMsg = new SLMessage.Inbound(); 42 | decodedMsg.readFromBuffer(msg.toBuffer()); 43 | assert.strictEqual(decodedMsg.senderId, 0); 44 | assert.strictEqual(decodedMsg.action, 0); 45 | assert.strictEqual(decodedMsg.dataLength, 0); 46 | } 47 | 48 | { 49 | let msg = new SLMessage.Outbound(0, 123); 50 | msg.createBaseMessage(); 51 | let decodedMsg = new SLMessage.Inbound(); 52 | decodedMsg.readFromBuffer(msg.toBuffer()); 53 | assert.strictEqual(decodedMsg.senderId, 123); 54 | assert.strictEqual(decodedMsg.action, 0); 55 | assert.strictEqual(decodedMsg.dataLength, 0); 56 | } 57 | }); 58 | 59 | it('encodes and decodes SLStrings', function() { 60 | { 61 | let msg = new SLMessage.Outbound(); 62 | msg.createBaseMessage(); 63 | let testStr = 'this is a test string'; 64 | msg.writeSLString(testStr); 65 | let decodedMsg = new SLMessage.Inbound(); 66 | decodedMsg.readFromBuffer(msg.toBuffer()); 67 | assert.strictEqual(decodedMsg.readSLString(), testStr, 'did not receive serialized message properly'); 68 | assert.strictEqual(SLMessage.SLMessage.slackForAlignment(testStr.length), 3); 69 | // SLString byte length = 4 + 21 + 3 = 28b 70 | assert.strictEqual(slMessageLen(testStr), 71 | 4 + testStr.length + SLMessage.SLMessage.slackForAlignment(testStr.length)); 72 | assert.strictEqual(decodedMsg.readOffset, msgHeaderLen + slMessageLen(testStr), 'read offset was invalid'); 73 | assert.strictEqual(decodedMsg.dataLength, decodedMsg.readOffset - 8); 74 | } 75 | 76 | { 77 | let msg = new SLMessage.Outbound(); 78 | msg.createBaseMessage(); 79 | let testStr = '1'; 80 | msg.writeSLString(testStr); 81 | let decodedMsg = new SLMessage.Inbound(); 82 | decodedMsg.readFromBuffer(msg.toBuffer()); 83 | assert.strictEqual(decodedMsg.readSLString(), testStr, 'did not receive serialized message properly'); 84 | assert.strictEqual(SLMessage.SLMessage.slackForAlignment(testStr.length), 3); 85 | assert.strictEqual(decodedMsg.readOffset, msgHeaderLen + slMessageLen(testStr), 'read offset was invalid'); 86 | assert.strictEqual(decodedMsg.dataLength, decodedMsg.readOffset - 8); 87 | } 88 | 89 | { 90 | let msg = new SLMessage.Outbound(); 91 | msg.createBaseMessage(); 92 | let testStr = '12'; 93 | msg.writeSLString(testStr); 94 | let decodedMsg = new SLMessage.Inbound(); 95 | decodedMsg.readFromBuffer(msg.toBuffer()); 96 | assert.strictEqual(decodedMsg.readSLString(), testStr, 'did not receive serialized message properly'); 97 | assert.strictEqual(SLMessage.SLMessage.slackForAlignment(testStr.length), 2); 98 | assert.strictEqual(decodedMsg.readOffset, msgHeaderLen + slMessageLen(testStr), 'read offset was invalid'); 99 | assert.strictEqual(decodedMsg.dataLength, decodedMsg.readOffset - 8); 100 | } 101 | 102 | { 103 | let msg = new SLMessage.Outbound(); 104 | msg.createBaseMessage(); 105 | let testStr = '123'; 106 | msg.writeSLString(testStr); 107 | let decodedMsg = new SLMessage.Inbound(); 108 | decodedMsg.readFromBuffer(msg.toBuffer()); 109 | assert.strictEqual(decodedMsg.readSLString(), testStr, 'did not receive serialized message properly'); 110 | assert.strictEqual(SLMessage.SLMessage.slackForAlignment(testStr.length), 1); 111 | assert.strictEqual(decodedMsg.readOffset, msgHeaderLen + slMessageLen(testStr), 'read offset was invalid'); 112 | assert.strictEqual(decodedMsg.dataLength, decodedMsg.readOffset - 8); 113 | } 114 | 115 | { 116 | let msg = new SLMessage.Outbound(); 117 | msg.createBaseMessage(); 118 | let testStr = '1234'; 119 | msg.writeSLString(testStr); 120 | let decodedMsg = new SLMessage.Inbound(); 121 | decodedMsg.readFromBuffer(msg.toBuffer()); 122 | assert.strictEqual(decodedMsg.readSLString(), testStr, 'did not receive serialized message properly'); 123 | assert.strictEqual(SLMessage.SLMessage.slackForAlignment(testStr.length), 0); 124 | assert.strictEqual(decodedMsg.readOffset, msgHeaderLen + slMessageLen(testStr), 'read offset was invalid'); 125 | assert.strictEqual(decodedMsg.dataLength, decodedMsg.readOffset - 8); 126 | } 127 | }); 128 | 129 | it('encodes and decodes SLArrays', function() { 130 | { 131 | let msg = new SLMessage.Outbound(); 132 | msg.createBaseMessage(); 133 | let list = []; 134 | msg.writeSLArray(list); 135 | let decodedMsg = new SLMessage.Inbound(); 136 | decodedMsg.readFromBuffer(msg.toBuffer()); 137 | assert.deepStrictEqual(decodedMsg.readSLArray(), list); 138 | assert.strictEqual(SLMessage.SLMessage.slackForAlignment(list.length), 0); 139 | assert.strictEqual(decodedMsg.readOffset, msgHeaderLen + slMessageLen(list), 'read offset was invalid'); 140 | assert.strictEqual(decodedMsg.dataLength, decodedMsg.readOffset - 8); 141 | } 142 | 143 | { 144 | let msg = new SLMessage.Outbound(); 145 | msg.createBaseMessage(); 146 | let list = [1]; 147 | msg.writeSLArray(list); 148 | let decodedMsg = new SLMessage.Inbound(); 149 | decodedMsg.readFromBuffer(msg.toBuffer()); 150 | assert.deepStrictEqual(decodedMsg.readSLArray(), list); 151 | assert.strictEqual(SLMessage.SLMessage.slackForAlignment(list.length), 3); 152 | assert.strictEqual(decodedMsg.readOffset, msgHeaderLen + slMessageLen(list), 'read offset was invalid'); 153 | assert.strictEqual(decodedMsg.dataLength, decodedMsg.readOffset - 8); 154 | } 155 | 156 | { 157 | let msg = new SLMessage.Outbound(); 158 | msg.createBaseMessage(); 159 | let list = [1, 2]; 160 | msg.writeSLArray(list); 161 | let decodedMsg = new SLMessage.Inbound(); 162 | decodedMsg.readFromBuffer(msg.toBuffer()); 163 | assert.deepStrictEqual(decodedMsg.readSLArray(), list); 164 | assert.strictEqual(SLMessage.SLMessage.slackForAlignment(list.length), 2); 165 | assert.strictEqual(decodedMsg.readOffset, msgHeaderLen + slMessageLen(list), 'read offset was invalid'); 166 | assert.strictEqual(decodedMsg.dataLength, decodedMsg.readOffset - 8); 167 | } 168 | 169 | { 170 | let msg = new SLMessage.Outbound(); 171 | msg.createBaseMessage(); 172 | let list = [1, 2, 3]; 173 | msg.writeSLArray(list); 174 | let decodedMsg = new SLMessage.Inbound(); 175 | decodedMsg.readFromBuffer(msg.toBuffer()); 176 | assert.deepStrictEqual(decodedMsg.readSLArray(), list); 177 | assert.strictEqual(SLMessage.SLMessage.slackForAlignment(list.length), 1); 178 | assert.strictEqual(decodedMsg.readOffset, msgHeaderLen + slMessageLen(list), 'read offset was invalid'); 179 | assert.strictEqual(decodedMsg.dataLength, decodedMsg.readOffset - 8); 180 | } 181 | 182 | { 183 | let msg = new SLMessage.Outbound(); 184 | msg.createBaseMessage(); 185 | let list = [1, 2, 3, 4]; 186 | msg.writeSLArray(list); 187 | let decodedMsg = new SLMessage.Inbound(); 188 | decodedMsg.readFromBuffer(msg.toBuffer()); 189 | assert.deepStrictEqual(decodedMsg.readSLArray(), list); 190 | assert.strictEqual(SLMessage.SLMessage.slackForAlignment(list.length), 0); 191 | assert.strictEqual(decodedMsg.readOffset, msgHeaderLen + slMessageLen(list), 'read offset was invalid'); 192 | assert.strictEqual(decodedMsg.dataLength, decodedMsg.readOffset - 8); 193 | } 194 | }); 195 | 196 | it('encodes Date as SLTime', function() { 197 | let msg = new SLMessage.Outbound(); 198 | msg.createBaseMessage(); 199 | let date = new Date(2021, 8, 6, 22, 8, 5); 200 | msg.writeSLDateTime(date); 201 | let decodedMsg = new SLMessage.Inbound(); 202 | decodedMsg.readFromBuffer(msg.toBuffer()); 203 | assert.equal(decodedMsg.readUInt16LE(), 2021); 204 | // javascript Date() month is 0-based, ScreenLogic month matches the calendar 205 | assert.equal(decodedMsg.readUInt16LE(), 9); 206 | // ScreenLogic day-of-week starts with Sunday as 1 207 | assert.equal(decodedMsg.readUInt16LE(), 2); 208 | assert.equal(decodedMsg.readUInt16LE(), 6); 209 | assert.equal(decodedMsg.readUInt16LE(), 22); 210 | assert.equal(decodedMsg.readUInt16LE(), 8); 211 | assert.equal(decodedMsg.readUInt16LE(), 5); 212 | assert.equal(decodedMsg.readUInt16LE(), 0); 213 | }); 214 | 215 | it('decodes SLTime as Date', function() { 216 | let msg = new SLMessage.Outbound(); 217 | msg.createBaseMessage(); 218 | let date = new Date(2021, 8, 6, 22, 8, 5); 219 | msg.writeSLDateTime(date); 220 | let decodedMsg = new SLMessage.Inbound(); 221 | decodedMsg.readFromBuffer(msg.toBuffer()); 222 | let decodedDate = decodedMsg.readSLDateTime(); 223 | assert.equal(date.getFullYear(), decodedDate.getFullYear()); 224 | assert.equal(date.getMonth(), decodedDate.getMonth()); 225 | assert.equal(date.getDate(), decodedDate.getDate()); 226 | assert.equal(date.getHours(), decodedDate.getHours()); 227 | assert.equal(date.getMinutes(), decodedDate.getMinutes()); 228 | assert.equal(date.getSeconds(), decodedDate.getSeconds()); 229 | assert.equal(date.getMilliseconds(), decodedDate.getMilliseconds()); 230 | }); 231 | 232 | it('writes the appropriate day of week', function() { 233 | let handler = function(inDate) { 234 | let msg = new SLMessage.Outbound(); 235 | msg.createBaseMessage(); 236 | msg.writeSLDateTime(inDate); 237 | let decodedMsg = new SLMessage.Inbound(); 238 | decodedMsg.readFromBuffer(msg.toBuffer()); 239 | decodedMsg.readUInt16LE(); 240 | decodedMsg.readUInt16LE(); 241 | return decodedMsg.readUInt16LE(); 242 | }; 243 | 244 | let dow = handler(new Date(2022, 3, 17, 10, 3, 0)); 245 | assert.equal(dow, 1); 246 | dow = handler(new Date(2022, 3, 18, 10, 3, 0)); 247 | assert.equal(dow, 2); 248 | dow = handler(new Date(2022, 3, 19, 10, 3, 0)); 249 | assert.equal(dow, 3); 250 | dow = handler(new Date(2022, 3, 20, 10, 3, 0)); 251 | assert.equal(dow, 4); 252 | dow = handler(new Date(2022, 3, 21, 10, 3, 0)); 253 | assert.equal(dow, 5); 254 | dow = handler(new Date(2022, 3, 22, 10, 3, 0)); 255 | assert.equal(dow, 6); 256 | dow = handler(new Date(2022, 3, 23, 10, 3, 0)); 257 | assert.equal(dow, 7); 258 | }); 259 | }); 260 | -------------------------------------------------------------------------------- /test/unit.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const ScreenLogic = require('../dist/index'); 4 | var assert = require('assert'); 5 | 6 | // you'll need a ScreenLogic-enabled device on your network for this to succeed 7 | describe('Unit', function() { 8 | let unit; 9 | before(function(done) { 10 | let finder = new ScreenLogic.FindUnits(); 11 | finder.on('serverFound', async server => { 12 | finder.close(); 13 | 14 | unit = new ScreenLogic.UnitConnection(); 15 | unit.initUnit(server); 16 | unit.once('loggedIn', () => { 17 | done(); 18 | }); 19 | 20 | try { 21 | if (!await unit.connectAsync()) { 22 | console.error('failed connection'); 23 | } 24 | } catch(err) { 25 | console.error(`caught error trying to connect: ${err}`); 26 | done(err); 27 | } 28 | }); 29 | 30 | finder.search(); 31 | }); 32 | 33 | after(async function() { 34 | await unit.closeAsync(); 35 | }); 36 | 37 | it('gets pool status', function(done) { 38 | unit.once('equipmentState', status => { 39 | assert.equal(status.senderId, 0); 40 | done(); 41 | }); 42 | 43 | unit.equipment.getEquipmentStateAsync(); 44 | }); 45 | 46 | it('gets controller config', function(done) { 47 | unit.once('controllerConfig', config => { 48 | assert.equal(config.senderId, 42); 49 | done(); 50 | }); 51 | 52 | unit.equipment.getControllerConfigAsync(42); 53 | }); 54 | 55 | it('gets chemical data', function(done) { 56 | unit.once('chemicalData', chemData => { 57 | assert.equal(chemData.senderId, 123); 58 | done(); 59 | }); 60 | 61 | unit.chem.getChemicalDataAsync(123); 62 | }); 63 | 64 | it('gets salt cell config', function(done) { 65 | unit.once('intellichlorConfig', saltConfig => { 66 | assert.equal(saltConfig.senderId, 0); 67 | done(); 68 | }); 69 | 70 | unit.chlor.getIntellichlorConfigAsync(); 71 | }); 72 | 73 | it('gets version', function(done) { 74 | unit.once('version', version => { 75 | assert.equal(version.senderId, 41239); 76 | done(); 77 | }); 78 | 79 | unit.getVersionAsync(41239); 80 | }); 81 | 82 | it('can add and remove a client', function(done) { 83 | unit.once('addClient', response => { 84 | assert.equal(response.senderId, 4321); 85 | unit.removeClientAsync(1234, 5432); 86 | }).once('removeClient', response => { 87 | assert.equal(response.senderId, 5432); 88 | done(); 89 | }); 90 | 91 | unit.addClientAsync(1234, 4321); 92 | }); 93 | 94 | it('can add and remove a client with async/await', async function() { 95 | const addClientResponse = await unit.addClientAsync(1234, 4321); 96 | assert.equal(addClientResponse.senderId, 4321); 97 | const removeClientResponse = await unit.removeClientAsync(1234, 5432); 98 | assert.equal(removeClientResponse.senderId, 5432); 99 | }); 100 | 101 | it('can ping the server', async () => { 102 | const pong = await unit.pingServerAsync(1122); 103 | assert.equal(pong.senderId, 1122); 104 | }); 105 | 106 | /* uncomment this to test setting state */ 107 | // it('sets circuit state', function(done) { 108 | // let circuit; 109 | // unit.once('equipmentState', (status) => { 110 | // circuit = status.circuitArray[0]; 111 | // unit.circuits.setCircuitStateAsync(circuit.id, circuit.state === 0 ? 1 : 0); 112 | // }).on('circuitStateChanged', (data) => { 113 | // done(); 114 | // }); 115 | 116 | // unit.equipment.getEquipmentStateAsync(); 117 | // }); 118 | }); 119 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowJs": false, 4 | "noImplicitAny": true, 5 | "module": "commonjs", 6 | "noEmitOnError": true, 7 | "removeComments": false, 8 | "sourceMap": true, 9 | "target": "ES2018", 10 | "preserveConstEnums": true, 11 | "outDir": "dist", 12 | "declaration": true 13 | }, 14 | "include": ["messages/**/*.ts", "*.ts", "index.ts", "utils/**/*.ts"], 15 | "exclude": [ 16 | "node_modules" 17 | ] 18 | } 19 | --------------------------------------------------------------------------------