Compare commits
54 Commits
Author | SHA1 | Date | |
---|---|---|---|
6013410525
|
|||
95140d112e
|
|||
db28ef4bbc
|
|||
c1ceacbd98
|
|||
9c72e7b61d | |||
def2d8aad4
|
|||
2d6d694aa5 | |||
a59fae5f8c
|
|||
f315bcd6a5
|
|||
a0e2569743
|
|||
9205e3b62b | |||
8e0cb20620
|
|||
98edd602ec
|
|||
ba1fb3fb6c
|
|||
6a1d31c224
|
|||
43725ae083
|
|||
81b3a61c28
|
|||
da9864462b
|
|||
a2d39e7463
|
|||
ed99d411b2
|
|||
5a55c56ac1
|
|||
e24f49285c
|
|||
ba19b6802e
|
|||
c9afb53810
|
|||
22357f11e2
|
|||
22858061f7
|
|||
9337068826
|
|||
0397e8ad8f
|
|||
c310885598
|
|||
661d8db173
|
|||
e567e9c821 | |||
b8ed58e070
|
|||
757a3be7d1 | |||
1dcbe3883b
|
|||
b95f6ff777
|
|||
5ec3fbb802
|
|||
3b774923eb
|
|||
64edc5879b
|
|||
cf3d3cba78
|
|||
1aa1dddb49
|
|||
3824437d7a | |||
cd2354c34f
|
|||
25188ddce9
|
|||
d70bc88f7c
|
|||
08c5457f2c
|
|||
398a687cc6
|
|||
8727d53440
|
|||
d3de4ec441
|
|||
605b8e4b4e
|
|||
a09df2569b
|
|||
ba734517c9
|
|||
3c6b8ebcc7
|
|||
26083f75a7
|
|||
aac316c5ed
|
12
.eslintrc.json
Normal file
12
.eslintrc.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"extends": "strongloop",
|
||||
"rules": {
|
||||
"max-len": [2, 120, 8]
|
||||
},
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 6
|
||||
},
|
||||
"env": {
|
||||
"mocha": true
|
||||
}
|
||||
}
|
29
.github/workflows/nodejs.yml
vendored
Normal file
29
.github/workflows/nodejs.yml
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
|
||||
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
|
||||
|
||||
name: Node.js CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [10.x, 12.x]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- run: npm ci
|
||||
- run: npm run build --if-present
|
||||
- run: npm run pretest
|
17
.vscode/launch.json
vendored
Normal file
17
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"name": "Example",
|
||||
"program": "${workspaceFolder}/example.js",
|
||||
"skipFiles": [
|
||||
"<node_internals>/**"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
61
CHANGELOG.md
Normal file
61
CHANGELOG.md
Normal file
@ -0,0 +1,61 @@
|
||||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## v1.5.0 - 2020-06-06
|
||||
### Added
|
||||
* Added support for adding, deleting, listing, and updating scheduled events
|
||||
* Added egg timer support
|
||||
|
||||
## v1.4.0 - 2020-05-25
|
||||
### Added
|
||||
* Support for controlling the salt cell generator's output levels.
|
||||
* Helper methods for interpreting `controllerType`.
|
||||
* 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.
|
||||
* `error` handler on all objects for reacting to unhandled node errors.
|
||||
|
||||
### Fixed
|
||||
* VSCode "Example" configuration can now be launched on non-Windows platforms.
|
||||
|
||||
### Changed
|
||||
* Minor memory/performance optimizations.
|
||||
* Running tests no longer changes any state of any pool equipment.
|
||||
|
||||
## v1.3.1 - 2019-12-27
|
||||
### Added
|
||||
* Several methods added to SLControllerConfigMessage for interpreting the equipFlags value.
|
||||
|
||||
### Fixed
|
||||
* server.gatewayName no longer cuts off the last character of the name. #14 - thanks @mikemucc
|
||||
|
||||
## v1.3.0 - 2019-11-26
|
||||
### Added
|
||||
* Ability to set heat setpoint.
|
||||
* Ability to set heat mode.
|
||||
* Event for supplying incorrect parameters to `set` functions.
|
||||
* Ability to send limited selection of light commands.
|
||||
|
||||
## v1.2.1 - 2019-03-26
|
||||
### Fixed
|
||||
* Messages larger than 1024 bytes are now handled properly.
|
||||
|
||||
## v1.2.0 - 2019-02-22
|
||||
### Added
|
||||
* Remote connection through Pentair servers
|
||||
* Connecting to password-protected systems (this is only enforced by the ScreenLogic system on remote connections)
|
||||
|
||||
## v1.1.0 - 2018-04-23
|
||||
### Added
|
||||
* Ability to set circuit state.
|
||||
|
||||
### Fixed
|
||||
* FindUnits.sendServerBroadcast() was failing in certain environments.
|
||||
|
||||
## v1.0.1 - 2018-03-31
|
||||
### Added
|
||||
* Direct connection support.
|
||||
|
||||
## v1.0.0 - 2018-03-31
|
||||
* Initial release
|
211
PasswordEncoder.js
Normal file
211
PasswordEncoder.js
Normal file
@ -0,0 +1,211 @@
|
||||
/* eslint max-len: "off" */
|
||||
|
||||
'use strict';
|
||||
|
||||
const BLOCK_SIZE = 16;
|
||||
const MAX_KC = 8;
|
||||
const MAX_ROUNDS = 14;
|
||||
|
||||
const sm_T1 = [ 0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d, 0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554, 0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d, 0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a, 0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87, 0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b, 0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea, 0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b, 0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a, 0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f, 0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108, 0xe2717193, 0xabd8d873, 0x62313153, 0x2a15153f, 0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e, 0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5, 0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d, 0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f, 0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e, 0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb, 0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce, 0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497, 0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c, 0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed, 0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b, 0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a, 0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16, 0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594, 0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81, 0xa05050f0, 0x783c3c44, 0x259f9fba, 0x4ba8a8e3, 0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a, 0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504, 0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163, 0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d, 0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f, 0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739, 0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47, 0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395, 0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f, 0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883, 0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c, 0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76, 0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e, 0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4, 0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6, 0x399191a8, 0x319595a4, 0xd3e4e437, 0xf279798b, 0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7, 0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0, 0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25, 0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818, 0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72, 0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651, 0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21, 0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85, 0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa, 0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12, 0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0, 0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9, 0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133, 0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7, 0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920, 0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a, 0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17, 0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8, 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11, 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a ];
|
||||
const sm_T2 = [ 0xa5c66363, 0x84f87c7c, 0x99ee7777, 0x8df67b7b, 0x0dfff2f2, 0xbdd66b6b, 0xb1de6f6f, 0x5491c5c5, 0x50603030, 0x03020101, 0xa9ce6767, 0x7d562b2b, 0x19e7fefe, 0x62b5d7d7, 0xe64dabab, 0x9aec7676, 0x458fcaca, 0x9d1f8282, 0x4089c9c9, 0x87fa7d7d, 0x15effafa, 0xebb25959, 0xc98e4747, 0x0bfbf0f0, 0xec41adad, 0x67b3d4d4, 0xfd5fa2a2, 0xea45afaf, 0xbf239c9c, 0xf753a4a4, 0x96e47272, 0x5b9bc0c0, 0xc275b7b7, 0x1ce1fdfd, 0xae3d9393, 0x6a4c2626, 0x5a6c3636, 0x417e3f3f, 0x02f5f7f7, 0x4f83cccc, 0x5c683434, 0xf451a5a5, 0x34d1e5e5, 0x08f9f1f1, 0x93e27171, 0x73abd8d8, 0x53623131, 0x3f2a1515, 0x0c080404, 0x5295c7c7, 0x65462323, 0x5e9dc3c3, 0x28301818, 0xa1379696, 0x0f0a0505, 0xb52f9a9a, 0x090e0707, 0x36241212, 0x9b1b8080, 0x3ddfe2e2, 0x26cdebeb, 0x694e2727, 0xcd7fb2b2, 0x9fea7575, 0x1b120909, 0x9e1d8383, 0x74582c2c, 0x2e341a1a, 0x2d361b1b, 0xb2dc6e6e, 0xeeb45a5a, 0xfb5ba0a0, 0xf6a45252, 0x4d763b3b, 0x61b7d6d6, 0xce7db3b3, 0x7b522929, 0x3edde3e3, 0x715e2f2f, 0x97138484, 0xf5a65353, 0x68b9d1d1, 0x00000000, 0x2cc1eded, 0x60402020, 0x1fe3fcfc, 0xc879b1b1, 0xedb65b5b, 0xbed46a6a, 0x468dcbcb, 0xd967bebe, 0x4b723939, 0xde944a4a, 0xd4984c4c, 0xe8b05858, 0x4a85cfcf, 0x6bbbd0d0, 0x2ac5efef, 0xe54faaaa, 0x16edfbfb, 0xc5864343, 0xd79a4d4d, 0x55663333, 0x94118585, 0xcf8a4545, 0x10e9f9f9, 0x06040202, 0x81fe7f7f, 0xf0a05050, 0x44783c3c, 0xba259f9f, 0xe34ba8a8, 0xf3a25151, 0xfe5da3a3, 0xc0804040, 0x8a058f8f, 0xad3f9292, 0xbc219d9d, 0x48703838, 0x04f1f5f5, 0xdf63bcbc, 0xc177b6b6, 0x75afdada, 0x63422121, 0x30201010, 0x1ae5ffff, 0x0efdf3f3, 0x6dbfd2d2, 0x4c81cdcd, 0x14180c0c, 0x35261313, 0x2fc3ecec, 0xe1be5f5f, 0xa2359797, 0xcc884444, 0x392e1717, 0x5793c4c4, 0xf255a7a7, 0x82fc7e7e, 0x477a3d3d, 0xacc86464, 0xe7ba5d5d, 0x2b321919, 0x95e67373, 0xa0c06060, 0x98198181, 0xd19e4f4f, 0x7fa3dcdc, 0x66442222, 0x7e542a2a, 0xab3b9090, 0x830b8888, 0xca8c4646, 0x29c7eeee, 0xd36bb8b8, 0x3c281414, 0x79a7dede, 0xe2bc5e5e, 0x1d160b0b, 0x76addbdb, 0x3bdbe0e0, 0x56643232, 0x4e743a3a, 0x1e140a0a, 0xdb924949, 0x0a0c0606, 0x6c482424, 0xe4b85c5c, 0x5d9fc2c2, 0x6ebdd3d3, 0xef43acac, 0xa6c46262, 0xa8399191, 0xa4319595, 0x37d3e4e4, 0x8bf27979, 0x32d5e7e7, 0x438bc8c8, 0x596e3737, 0xb7da6d6d, 0x8c018d8d, 0x64b1d5d5, 0xd29c4e4e, 0xe049a9a9, 0xb4d86c6c, 0xfaac5656, 0x07f3f4f4, 0x25cfeaea, 0xafca6565, 0x8ef47a7a, 0xe947aeae, 0x18100808, 0xd56fbaba, 0x88f07878, 0x6f4a2525, 0x725c2e2e, 0x24381c1c, 0xf157a6a6, 0xc773b4b4, 0x5197c6c6, 0x23cbe8e8, 0x7ca1dddd, 0x9ce87474, 0x213e1f1f, 0xdd964b4b, 0xdc61bdbd, 0x860d8b8b, 0x850f8a8a, 0x90e07070, 0x427c3e3e, 0xc471b5b5, 0xaacc6666, 0xd8904848, 0x05060303, 0x01f7f6f6, 0x121c0e0e, 0xa3c26161, 0x5f6a3535, 0xf9ae5757, 0xd069b9b9, 0x91178686, 0x5899c1c1, 0x273a1d1d, 0xb9279e9e, 0x38d9e1e1, 0x13ebf8f8, 0xb32b9898, 0x33221111, 0xbbd26969, 0x70a9d9d9, 0x89078e8e, 0xa7339494, 0xb62d9b9b, 0x223c1e1e, 0x92158787, 0x20c9e9e9, 0x4987cece, 0xffaa5555, 0x78502828, 0x7aa5dfdf, 0x8f038c8c, 0xf859a1a1, 0x80098989, 0x171a0d0d, 0xda65bfbf, 0x31d7e6e6, 0xc6844242, 0xb8d06868, 0xc3824141, 0xb0299999, 0x775a2d2d, 0x111e0f0f, 0xcb7bb0b0, 0xfca85454, 0xd66dbbbb, 0x3a2c1616 ];
|
||||
const sm_T3 = [ 0x63a5c663, 0x7c84f87c, 0x7799ee77, 0x7b8df67b, 0xf20dfff2, 0x6bbdd66b, 0x6fb1de6f, 0xc55491c5, 0x30506030, 0x01030201, 0x67a9ce67, 0x2b7d562b, 0xfe19e7fe, 0xd762b5d7, 0xabe64dab, 0x769aec76, 0xca458fca, 0x829d1f82, 0xc94089c9, 0x7d87fa7d, 0xfa15effa, 0x59ebb259, 0x47c98e47, 0xf00bfbf0, 0xadec41ad, 0xd467b3d4, 0xa2fd5fa2, 0xafea45af, 0x9cbf239c, 0xa4f753a4, 0x7296e472, 0xc05b9bc0, 0xb7c275b7, 0xfd1ce1fd, 0x93ae3d93, 0x266a4c26, 0x365a6c36, 0x3f417e3f, 0xf702f5f7, 0xcc4f83cc, 0x345c6834, 0xa5f451a5, 0xe534d1e5, 0xf108f9f1, 0x7193e271, 0xd873abd8, 0x31536231, 0x153f2a15, 0x040c0804, 0xc75295c7, 0x23654623, 0xc35e9dc3, 0x18283018, 0x96a13796, 0x050f0a05, 0x9ab52f9a, 0x07090e07, 0x12362412, 0x809b1b80, 0xe23ddfe2, 0xeb26cdeb, 0x27694e27, 0xb2cd7fb2, 0x759fea75, 0x091b1209, 0x839e1d83, 0x2c74582c, 0x1a2e341a, 0x1b2d361b, 0x6eb2dc6e, 0x5aeeb45a, 0xa0fb5ba0, 0x52f6a452, 0x3b4d763b, 0xd661b7d6, 0xb3ce7db3, 0x297b5229, 0xe33edde3, 0x2f715e2f, 0x84971384, 0x53f5a653, 0xd168b9d1, 0x00000000, 0xed2cc1ed, 0x20604020, 0xfc1fe3fc, 0xb1c879b1, 0x5bedb65b, 0x6abed46a, 0xcb468dcb, 0xbed967be, 0x394b7239, 0x4ade944a, 0x4cd4984c, 0x58e8b058, 0xcf4a85cf, 0xd06bbbd0, 0xef2ac5ef, 0xaae54faa, 0xfb16edfb, 0x43c58643, 0x4dd79a4d, 0x33556633, 0x85941185, 0x45cf8a45, 0xf910e9f9, 0x02060402, 0x7f81fe7f, 0x50f0a050, 0x3c44783c, 0x9fba259f, 0xa8e34ba8, 0x51f3a251, 0xa3fe5da3, 0x40c08040, 0x8f8a058f, 0x92ad3f92, 0x9dbc219d, 0x38487038, 0xf504f1f5, 0xbcdf63bc, 0xb6c177b6, 0xda75afda, 0x21634221, 0x10302010, 0xff1ae5ff, 0xf30efdf3, 0xd26dbfd2, 0xcd4c81cd, 0x0c14180c, 0x13352613, 0xec2fc3ec, 0x5fe1be5f, 0x97a23597, 0x44cc8844, 0x17392e17, 0xc45793c4, 0xa7f255a7, 0x7e82fc7e, 0x3d477a3d, 0x64acc864, 0x5de7ba5d, 0x192b3219, 0x7395e673, 0x60a0c060, 0x81981981, 0x4fd19e4f, 0xdc7fa3dc, 0x22664422, 0x2a7e542a, 0x90ab3b90, 0x88830b88, 0x46ca8c46, 0xee29c7ee, 0xb8d36bb8, 0x143c2814, 0xde79a7de, 0x5ee2bc5e, 0x0b1d160b, 0xdb76addb, 0xe03bdbe0, 0x32566432, 0x3a4e743a, 0x0a1e140a, 0x49db9249, 0x060a0c06, 0x246c4824, 0x5ce4b85c, 0xc25d9fc2, 0xd36ebdd3, 0xacef43ac, 0x62a6c462, 0x91a83991, 0x95a43195, 0xe437d3e4, 0x798bf279, 0xe732d5e7, 0xc8438bc8, 0x37596e37, 0x6db7da6d, 0x8d8c018d, 0xd564b1d5, 0x4ed29c4e, 0xa9e049a9, 0x6cb4d86c, 0x56faac56, 0xf407f3f4, 0xea25cfea, 0x65afca65, 0x7a8ef47a, 0xaee947ae, 0x08181008, 0xbad56fba, 0x7888f078, 0x256f4a25, 0x2e725c2e, 0x1c24381c, 0xa6f157a6, 0xb4c773b4, 0xc65197c6, 0xe823cbe8, 0xdd7ca1dd, 0x749ce874, 0x1f213e1f, 0x4bdd964b, 0xbddc61bd, 0x8b860d8b, 0x8a850f8a, 0x7090e070, 0x3e427c3e, 0xb5c471b5, 0x66aacc66, 0x48d89048, 0x03050603, 0xf601f7f6, 0x0e121c0e, 0x61a3c261, 0x355f6a35, 0x57f9ae57, 0xb9d069b9, 0x86911786, 0xc15899c1, 0x1d273a1d, 0x9eb9279e, 0xe138d9e1, 0xf813ebf8, 0x98b32b98, 0x11332211, 0x69bbd269, 0xd970a9d9, 0x8e89078e, 0x94a73394, 0x9bb62d9b, 0x1e223c1e, 0x87921587, 0xe920c9e9, 0xce4987ce, 0x55ffaa55, 0x28785028, 0xdf7aa5df, 0x8c8f038c, 0xa1f859a1, 0x89800989, 0x0d171a0d, 0xbfda65bf, 0xe631d7e6, 0x42c68442, 0x68b8d068, 0x41c38241, 0x99b02999, 0x2d775a2d, 0x0f111e0f, 0xb0cb7bb0, 0x54fca854, 0xbbd66dbb, 0x163a2c16 ];
|
||||
const sm_T4 = [ 0x6363a5c6, 0x7c7c84f8, 0x777799ee, 0x7b7b8df6, 0xf2f20dff, 0x6b6bbdd6, 0x6f6fb1de, 0xc5c55491, 0x30305060, 0x01010302, 0x6767a9ce, 0x2b2b7d56, 0xfefe19e7, 0xd7d762b5, 0xababe64d, 0x76769aec, 0xcaca458f, 0x82829d1f, 0xc9c94089, 0x7d7d87fa, 0xfafa15ef, 0x5959ebb2, 0x4747c98e, 0xf0f00bfb, 0xadadec41, 0xd4d467b3, 0xa2a2fd5f, 0xafafea45, 0x9c9cbf23, 0xa4a4f753, 0x727296e4, 0xc0c05b9b, 0xb7b7c275, 0xfdfd1ce1, 0x9393ae3d, 0x26266a4c, 0x36365a6c, 0x3f3f417e, 0xf7f702f5, 0xcccc4f83, 0x34345c68, 0xa5a5f451, 0xe5e534d1, 0xf1f108f9, 0x717193e2, 0xd8d873ab, 0x31315362, 0x15153f2a, 0x04040c08, 0xc7c75295, 0x23236546, 0xc3c35e9d, 0x18182830, 0x9696a137, 0x05050f0a, 0x9a9ab52f, 0x0707090e, 0x12123624, 0x80809b1b, 0xe2e23ddf, 0xebeb26cd, 0x2727694e, 0xb2b2cd7f, 0x75759fea, 0x09091b12, 0x83839e1d, 0x2c2c7458, 0x1a1a2e34, 0x1b1b2d36, 0x6e6eb2dc, 0x5a5aeeb4, 0xa0a0fb5b, 0x5252f6a4, 0x3b3b4d76, 0xd6d661b7, 0xb3b3ce7d, 0x29297b52, 0xe3e33edd, 0x2f2f715e, 0x84849713, 0x5353f5a6, 0xd1d168b9, 0x00000000, 0xeded2cc1, 0x20206040, 0xfcfc1fe3, 0xb1b1c879, 0x5b5bedb6, 0x6a6abed4, 0xcbcb468d, 0xbebed967, 0x39394b72, 0x4a4ade94, 0x4c4cd498, 0x5858e8b0, 0xcfcf4a85, 0xd0d06bbb, 0xefef2ac5, 0xaaaae54f, 0xfbfb16ed, 0x4343c586, 0x4d4dd79a, 0x33335566, 0x85859411, 0x4545cf8a, 0xf9f910e9, 0x02020604, 0x7f7f81fe, 0x5050f0a0, 0x3c3c4478, 0x9f9fba25, 0xa8a8e34b, 0x5151f3a2, 0xa3a3fe5d, 0x4040c080, 0x8f8f8a05, 0x9292ad3f, 0x9d9dbc21, 0x38384870, 0xf5f504f1, 0xbcbcdf63, 0xb6b6c177, 0xdada75af, 0x21216342, 0x10103020, 0xffff1ae5, 0xf3f30efd, 0xd2d26dbf, 0xcdcd4c81, 0x0c0c1418, 0x13133526, 0xecec2fc3, 0x5f5fe1be, 0x9797a235, 0x4444cc88, 0x1717392e, 0xc4c45793, 0xa7a7f255, 0x7e7e82fc, 0x3d3d477a, 0x6464acc8, 0x5d5de7ba, 0x19192b32, 0x737395e6, 0x6060a0c0, 0x81819819, 0x4f4fd19e, 0xdcdc7fa3, 0x22226644, 0x2a2a7e54, 0x9090ab3b, 0x8888830b, 0x4646ca8c, 0xeeee29c7, 0xb8b8d36b, 0x14143c28, 0xdede79a7, 0x5e5ee2bc, 0x0b0b1d16, 0xdbdb76ad, 0xe0e03bdb, 0x32325664, 0x3a3a4e74, 0x0a0a1e14, 0x4949db92, 0x06060a0c, 0x24246c48, 0x5c5ce4b8, 0xc2c25d9f, 0xd3d36ebd, 0xacacef43, 0x6262a6c4, 0x9191a839, 0x9595a431, 0xe4e437d3, 0x79798bf2, 0xe7e732d5, 0xc8c8438b, 0x3737596e, 0x6d6db7da, 0x8d8d8c01, 0xd5d564b1, 0x4e4ed29c, 0xa9a9e049, 0x6c6cb4d8, 0x5656faac, 0xf4f407f3, 0xeaea25cf, 0x6565afca, 0x7a7a8ef4, 0xaeaee947, 0x08081810, 0xbabad56f, 0x787888f0, 0x25256f4a, 0x2e2e725c, 0x1c1c2438, 0xa6a6f157, 0xb4b4c773, 0xc6c65197, 0xe8e823cb, 0xdddd7ca1, 0x74749ce8, 0x1f1f213e, 0x4b4bdd96, 0xbdbddc61, 0x8b8b860d, 0x8a8a850f, 0x707090e0, 0x3e3e427c, 0xb5b5c471, 0x6666aacc, 0x4848d890, 0x03030506, 0xf6f601f7, 0x0e0e121c, 0x6161a3c2, 0x35355f6a, 0x5757f9ae, 0xb9b9d069, 0x86869117, 0xc1c15899, 0x1d1d273a, 0x9e9eb927, 0xe1e138d9, 0xf8f813eb, 0x9898b32b, 0x11113322, 0x6969bbd2, 0xd9d970a9, 0x8e8e8907, 0x9494a733, 0x9b9bb62d, 0x1e1e223c, 0x87879215, 0xe9e920c9, 0xcece4987, 0x5555ffaa, 0x28287850, 0xdfdf7aa5, 0x8c8c8f03, 0xa1a1f859, 0x89898009, 0x0d0d171a, 0xbfbfda65, 0xe6e631d7, 0x4242c684, 0x6868b8d0, 0x4141c382, 0x9999b029, 0x2d2d775a, 0x0f0f111e, 0xb0b0cb7b, 0x5454fca8, 0xbbbbd66d, 0x16163a2c ];
|
||||
const sm_U1 = [ 0x00000000, 0x0e090d0b, 0x1c121a16, 0x121b171d, 0x3824342c, 0x362d3927, 0x24362e3a, 0x2a3f2331, 0x70486858, 0x7e416553, 0x6c5a724e, 0x62537f45, 0x486c5c74, 0x4665517f, 0x547e4662, 0x5a774b69, 0xe090d0b0, 0xee99ddbb, 0xfc82caa6, 0xf28bc7ad, 0xd8b4e49c, 0xd6bde997, 0xc4a6fe8a, 0xcaaff381, 0x90d8b8e8, 0x9ed1b5e3, 0x8ccaa2fe, 0x82c3aff5, 0xa8fc8cc4, 0xa6f581cf, 0xb4ee96d2, 0xbae79bd9, 0xdb3bbb7b, 0xd532b670, 0xc729a16d, 0xc920ac66, 0xe31f8f57, 0xed16825c, 0xff0d9541, 0xf104984a, 0xab73d323, 0xa57ade28, 0xb761c935, 0xb968c43e, 0x9357e70f, 0x9d5eea04, 0x8f45fd19, 0x814cf012, 0x3bab6bcb, 0x35a266c0, 0x27b971dd, 0x29b07cd6, 0x038f5fe7, 0x0d8652ec, 0x1f9d45f1, 0x119448fa, 0x4be30393, 0x45ea0e98, 0x57f11985, 0x59f8148e, 0x73c737bf, 0x7dce3ab4, 0x6fd52da9, 0x61dc20a2, 0xad766df6, 0xa37f60fd, 0xb16477e0, 0xbf6d7aeb, 0x955259da, 0x9b5b54d1, 0x894043cc, 0x87494ec7, 0xdd3e05ae, 0xd33708a5, 0xc12c1fb8, 0xcf2512b3, 0xe51a3182, 0xeb133c89, 0xf9082b94, 0xf701269f, 0x4de6bd46, 0x43efb04d, 0x51f4a750, 0x5ffdaa5b, 0x75c2896a, 0x7bcb8461, 0x69d0937c, 0x67d99e77, 0x3daed51e, 0x33a7d815, 0x21bccf08, 0x2fb5c203, 0x058ae132, 0x0b83ec39, 0x1998fb24, 0x1791f62f, 0x764dd68d, 0x7844db86, 0x6a5fcc9b, 0x6456c190, 0x4e69e2a1, 0x4060efaa, 0x527bf8b7, 0x5c72f5bc, 0x0605bed5, 0x080cb3de, 0x1a17a4c3, 0x141ea9c8, 0x3e218af9, 0x302887f2, 0x223390ef, 0x2c3a9de4, 0x96dd063d, 0x98d40b36, 0x8acf1c2b, 0x84c61120, 0xaef93211, 0xa0f03f1a, 0xb2eb2807, 0xbce2250c, 0xe6956e65, 0xe89c636e, 0xfa877473, 0xf48e7978, 0xdeb15a49, 0xd0b85742, 0xc2a3405f, 0xccaa4d54, 0x41ecdaf7, 0x4fe5d7fc, 0x5dfec0e1, 0x53f7cdea, 0x79c8eedb, 0x77c1e3d0, 0x65daf4cd, 0x6bd3f9c6, 0x31a4b2af, 0x3fadbfa4, 0x2db6a8b9, 0x23bfa5b2, 0x09808683, 0x07898b88, 0x15929c95, 0x1b9b919e, 0xa17c0a47, 0xaf75074c, 0xbd6e1051, 0xb3671d5a, 0x99583e6b, 0x97513360, 0x854a247d, 0x8b432976, 0xd134621f, 0xdf3d6f14, 0xcd267809, 0xc32f7502, 0xe9105633, 0xe7195b38, 0xf5024c25, 0xfb0b412e, 0x9ad7618c, 0x94de6c87, 0x86c57b9a, 0x88cc7691, 0xa2f355a0, 0xacfa58ab, 0xbee14fb6, 0xb0e842bd, 0xea9f09d4, 0xe49604df, 0xf68d13c2, 0xf8841ec9, 0xd2bb3df8, 0xdcb230f3, 0xcea927ee, 0xc0a02ae5, 0x7a47b13c, 0x744ebc37, 0x6655ab2a, 0x685ca621, 0x42638510, 0x4c6a881b, 0x5e719f06, 0x5078920d, 0x0a0fd964, 0x0406d46f, 0x161dc372, 0x1814ce79, 0x322bed48, 0x3c22e043, 0x2e39f75e, 0x2030fa55, 0xec9ab701, 0xe293ba0a, 0xf088ad17, 0xfe81a01c, 0xd4be832d, 0xdab78e26, 0xc8ac993b, 0xc6a59430, 0x9cd2df59, 0x92dbd252, 0x80c0c54f, 0x8ec9c844, 0xa4f6eb75, 0xaaffe67e, 0xb8e4f163, 0xb6edfc68, 0x0c0a67b1, 0x02036aba, 0x10187da7, 0x1e1170ac, 0x342e539d, 0x3a275e96, 0x283c498b, 0x26354480, 0x7c420fe9, 0x724b02e2, 0x605015ff, 0x6e5918f4, 0x44663bc5, 0x4a6f36ce, 0x587421d3, 0x567d2cd8, 0x37a10c7a, 0x39a80171, 0x2bb3166c, 0x25ba1b67, 0x0f853856, 0x018c355d, 0x13972240, 0x1d9e2f4b, 0x47e96422, 0x49e06929, 0x5bfb7e34, 0x55f2733f, 0x7fcd500e, 0x71c45d05, 0x63df4a18, 0x6dd64713, 0xd731dcca, 0xd938d1c1, 0xcb23c6dc, 0xc52acbd7, 0xef15e8e6, 0xe11ce5ed, 0xf307f2f0, 0xfd0efffb, 0xa779b492, 0xa970b999, 0xbb6bae84, 0xb562a38f, 0x9f5d80be, 0x91548db5, 0x834f9aa8, 0x8d4697a3 ];
|
||||
const sm_U2 = [ 0x00000000, 0x0b0e090d, 0x161c121a, 0x1d121b17, 0x2c382434, 0x27362d39, 0x3a24362e, 0x312a3f23, 0x58704868, 0x537e4165, 0x4e6c5a72, 0x4562537f, 0x74486c5c, 0x7f466551, 0x62547e46, 0x695a774b, 0xb0e090d0, 0xbbee99dd, 0xa6fc82ca, 0xadf28bc7, 0x9cd8b4e4, 0x97d6bde9, 0x8ac4a6fe, 0x81caaff3, 0xe890d8b8, 0xe39ed1b5, 0xfe8ccaa2, 0xf582c3af, 0xc4a8fc8c, 0xcfa6f581, 0xd2b4ee96, 0xd9bae79b, 0x7bdb3bbb, 0x70d532b6, 0x6dc729a1, 0x66c920ac, 0x57e31f8f, 0x5ced1682, 0x41ff0d95, 0x4af10498, 0x23ab73d3, 0x28a57ade, 0x35b761c9, 0x3eb968c4, 0x0f9357e7, 0x049d5eea, 0x198f45fd, 0x12814cf0, 0xcb3bab6b, 0xc035a266, 0xdd27b971, 0xd629b07c, 0xe7038f5f, 0xec0d8652, 0xf11f9d45, 0xfa119448, 0x934be303, 0x9845ea0e, 0x8557f119, 0x8e59f814, 0xbf73c737, 0xb47dce3a, 0xa96fd52d, 0xa261dc20, 0xf6ad766d, 0xfda37f60, 0xe0b16477, 0xebbf6d7a, 0xda955259, 0xd19b5b54, 0xcc894043, 0xc787494e, 0xaedd3e05, 0xa5d33708, 0xb8c12c1f, 0xb3cf2512, 0x82e51a31, 0x89eb133c, 0x94f9082b, 0x9ff70126, 0x464de6bd, 0x4d43efb0, 0x5051f4a7, 0x5b5ffdaa, 0x6a75c289, 0x617bcb84, 0x7c69d093, 0x7767d99e, 0x1e3daed5, 0x1533a7d8, 0x0821bccf, 0x032fb5c2, 0x32058ae1, 0x390b83ec, 0x241998fb, 0x2f1791f6, 0x8d764dd6, 0x867844db, 0x9b6a5fcc, 0x906456c1, 0xa14e69e2, 0xaa4060ef, 0xb7527bf8, 0xbc5c72f5, 0xd50605be, 0xde080cb3, 0xc31a17a4, 0xc8141ea9, 0xf93e218a, 0xf2302887, 0xef223390, 0xe42c3a9d, 0x3d96dd06, 0x3698d40b, 0x2b8acf1c, 0x2084c611, 0x11aef932, 0x1aa0f03f, 0x07b2eb28, 0x0cbce225, 0x65e6956e, 0x6ee89c63, 0x73fa8774, 0x78f48e79, 0x49deb15a, 0x42d0b857, 0x5fc2a340, 0x54ccaa4d, 0xf741ecda, 0xfc4fe5d7, 0xe15dfec0, 0xea53f7cd, 0xdb79c8ee, 0xd077c1e3, 0xcd65daf4, 0xc66bd3f9, 0xaf31a4b2, 0xa43fadbf, 0xb92db6a8, 0xb223bfa5, 0x83098086, 0x8807898b, 0x9515929c, 0x9e1b9b91, 0x47a17c0a, 0x4caf7507, 0x51bd6e10, 0x5ab3671d, 0x6b99583e, 0x60975133, 0x7d854a24, 0x768b4329, 0x1fd13462, 0x14df3d6f, 0x09cd2678, 0x02c32f75, 0x33e91056, 0x38e7195b, 0x25f5024c, 0x2efb0b41, 0x8c9ad761, 0x8794de6c, 0x9a86c57b, 0x9188cc76, 0xa0a2f355, 0xabacfa58, 0xb6bee14f, 0xbdb0e842, 0xd4ea9f09, 0xdfe49604, 0xc2f68d13, 0xc9f8841e, 0xf8d2bb3d, 0xf3dcb230, 0xeecea927, 0xe5c0a02a, 0x3c7a47b1, 0x37744ebc, 0x2a6655ab, 0x21685ca6, 0x10426385, 0x1b4c6a88, 0x065e719f, 0x0d507892, 0x640a0fd9, 0x6f0406d4, 0x72161dc3, 0x791814ce, 0x48322bed, 0x433c22e0, 0x5e2e39f7, 0x552030fa, 0x01ec9ab7, 0x0ae293ba, 0x17f088ad, 0x1cfe81a0, 0x2dd4be83, 0x26dab78e, 0x3bc8ac99, 0x30c6a594, 0x599cd2df, 0x5292dbd2, 0x4f80c0c5, 0x448ec9c8, 0x75a4f6eb, 0x7eaaffe6, 0x63b8e4f1, 0x68b6edfc, 0xb10c0a67, 0xba02036a, 0xa710187d, 0xac1e1170, 0x9d342e53, 0x963a275e, 0x8b283c49, 0x80263544, 0xe97c420f, 0xe2724b02, 0xff605015, 0xf46e5918, 0xc544663b, 0xce4a6f36, 0xd3587421, 0xd8567d2c, 0x7a37a10c, 0x7139a801, 0x6c2bb316, 0x6725ba1b, 0x560f8538, 0x5d018c35, 0x40139722, 0x4b1d9e2f, 0x2247e964, 0x2949e069, 0x345bfb7e, 0x3f55f273, 0x0e7fcd50, 0x0571c45d, 0x1863df4a, 0x136dd647, 0xcad731dc, 0xc1d938d1, 0xdccb23c6, 0xd7c52acb, 0xe6ef15e8, 0xede11ce5, 0xf0f307f2, 0xfbfd0eff, 0x92a779b4, 0x99a970b9, 0x84bb6bae, 0x8fb562a3, 0xbe9f5d80, 0xb591548d, 0xa8834f9a, 0xa38d4697 ];
|
||||
const sm_U3 = [ 0x00000000, 0x0d0b0e09, 0x1a161c12, 0x171d121b, 0x342c3824, 0x3927362d, 0x2e3a2436, 0x23312a3f, 0x68587048, 0x65537e41, 0x724e6c5a, 0x7f456253, 0x5c74486c, 0x517f4665, 0x4662547e, 0x4b695a77, 0xd0b0e090, 0xddbbee99, 0xcaa6fc82, 0xc7adf28b, 0xe49cd8b4, 0xe997d6bd, 0xfe8ac4a6, 0xf381caaf, 0xb8e890d8, 0xb5e39ed1, 0xa2fe8cca, 0xaff582c3, 0x8cc4a8fc, 0x81cfa6f5, 0x96d2b4ee, 0x9bd9bae7, 0xbb7bdb3b, 0xb670d532, 0xa16dc729, 0xac66c920, 0x8f57e31f, 0x825ced16, 0x9541ff0d, 0x984af104, 0xd323ab73, 0xde28a57a, 0xc935b761, 0xc43eb968, 0xe70f9357, 0xea049d5e, 0xfd198f45, 0xf012814c, 0x6bcb3bab, 0x66c035a2, 0x71dd27b9, 0x7cd629b0, 0x5fe7038f, 0x52ec0d86, 0x45f11f9d, 0x48fa1194, 0x03934be3, 0x0e9845ea, 0x198557f1, 0x148e59f8, 0x37bf73c7, 0x3ab47dce, 0x2da96fd5, 0x20a261dc, 0x6df6ad76, 0x60fda37f, 0x77e0b164, 0x7aebbf6d, 0x59da9552, 0x54d19b5b, 0x43cc8940, 0x4ec78749, 0x05aedd3e, 0x08a5d337, 0x1fb8c12c, 0x12b3cf25, 0x3182e51a, 0x3c89eb13, 0x2b94f908, 0x269ff701, 0xbd464de6, 0xb04d43ef, 0xa75051f4, 0xaa5b5ffd, 0x896a75c2, 0x84617bcb, 0x937c69d0, 0x9e7767d9, 0xd51e3dae, 0xd81533a7, 0xcf0821bc, 0xc2032fb5, 0xe132058a, 0xec390b83, 0xfb241998, 0xf62f1791, 0xd68d764d, 0xdb867844, 0xcc9b6a5f, 0xc1906456, 0xe2a14e69, 0xefaa4060, 0xf8b7527b, 0xf5bc5c72, 0xbed50605, 0xb3de080c, 0xa4c31a17, 0xa9c8141e, 0x8af93e21, 0x87f23028, 0x90ef2233, 0x9de42c3a, 0x063d96dd, 0x0b3698d4, 0x1c2b8acf, 0x112084c6, 0x3211aef9, 0x3f1aa0f0, 0x2807b2eb, 0x250cbce2, 0x6e65e695, 0x636ee89c, 0x7473fa87, 0x7978f48e, 0x5a49deb1, 0x5742d0b8, 0x405fc2a3, 0x4d54ccaa, 0xdaf741ec, 0xd7fc4fe5, 0xc0e15dfe, 0xcdea53f7, 0xeedb79c8, 0xe3d077c1, 0xf4cd65da, 0xf9c66bd3, 0xb2af31a4, 0xbfa43fad, 0xa8b92db6, 0xa5b223bf, 0x86830980, 0x8b880789, 0x9c951592, 0x919e1b9b, 0x0a47a17c, 0x074caf75, 0x1051bd6e, 0x1d5ab367, 0x3e6b9958, 0x33609751, 0x247d854a, 0x29768b43, 0x621fd134, 0x6f14df3d, 0x7809cd26, 0x7502c32f, 0x5633e910, 0x5b38e719, 0x4c25f502, 0x412efb0b, 0x618c9ad7, 0x6c8794de, 0x7b9a86c5, 0x769188cc, 0x55a0a2f3, 0x58abacfa, 0x4fb6bee1, 0x42bdb0e8, 0x09d4ea9f, 0x04dfe496, 0x13c2f68d, 0x1ec9f884, 0x3df8d2bb, 0x30f3dcb2, 0x27eecea9, 0x2ae5c0a0, 0xb13c7a47, 0xbc37744e, 0xab2a6655, 0xa621685c, 0x85104263, 0x881b4c6a, 0x9f065e71, 0x920d5078, 0xd9640a0f, 0xd46f0406, 0xc372161d, 0xce791814, 0xed48322b, 0xe0433c22, 0xf75e2e39, 0xfa552030, 0xb701ec9a, 0xba0ae293, 0xad17f088, 0xa01cfe81, 0x832dd4be, 0x8e26dab7, 0x993bc8ac, 0x9430c6a5, 0xdf599cd2, 0xd25292db, 0xc54f80c0, 0xc8448ec9, 0xeb75a4f6, 0xe67eaaff, 0xf163b8e4, 0xfc68b6ed, 0x67b10c0a, 0x6aba0203, 0x7da71018, 0x70ac1e11, 0x539d342e, 0x5e963a27, 0x498b283c, 0x44802635, 0x0fe97c42, 0x02e2724b, 0x15ff6050, 0x18f46e59, 0x3bc54466, 0x36ce4a6f, 0x21d35874, 0x2cd8567d, 0x0c7a37a1, 0x017139a8, 0x166c2bb3, 0x1b6725ba, 0x38560f85, 0x355d018c, 0x22401397, 0x2f4b1d9e, 0x642247e9, 0x692949e0, 0x7e345bfb, 0x733f55f2, 0x500e7fcd, 0x5d0571c4, 0x4a1863df, 0x47136dd6, 0xdccad731, 0xd1c1d938, 0xc6dccb23, 0xcbd7c52a, 0xe8e6ef15, 0xe5ede11c, 0xf2f0f307, 0xfffbfd0e, 0xb492a779, 0xb999a970, 0xae84bb6b, 0xa38fb562, 0x80be9f5d, 0x8db59154, 0x9aa8834f, 0x97a38d46 ];
|
||||
const sm_U4 = [ 0x00000000, 0x090d0b0e, 0x121a161c, 0x1b171d12, 0x24342c38, 0x2d392736, 0x362e3a24, 0x3f23312a, 0x48685870, 0x4165537e, 0x5a724e6c, 0x537f4562, 0x6c5c7448, 0x65517f46, 0x7e466254, 0x774b695a, 0x90d0b0e0, 0x99ddbbee, 0x82caa6fc, 0x8bc7adf2, 0xb4e49cd8, 0xbde997d6, 0xa6fe8ac4, 0xaff381ca, 0xd8b8e890, 0xd1b5e39e, 0xcaa2fe8c, 0xc3aff582, 0xfc8cc4a8, 0xf581cfa6, 0xee96d2b4, 0xe79bd9ba, 0x3bbb7bdb, 0x32b670d5, 0x29a16dc7, 0x20ac66c9, 0x1f8f57e3, 0x16825ced, 0x0d9541ff, 0x04984af1, 0x73d323ab, 0x7ade28a5, 0x61c935b7, 0x68c43eb9, 0x57e70f93, 0x5eea049d, 0x45fd198f, 0x4cf01281, 0xab6bcb3b, 0xa266c035, 0xb971dd27, 0xb07cd629, 0x8f5fe703, 0x8652ec0d, 0x9d45f11f, 0x9448fa11, 0xe303934b, 0xea0e9845, 0xf1198557, 0xf8148e59, 0xc737bf73, 0xce3ab47d, 0xd52da96f, 0xdc20a261, 0x766df6ad, 0x7f60fda3, 0x6477e0b1, 0x6d7aebbf, 0x5259da95, 0x5b54d19b, 0x4043cc89, 0x494ec787, 0x3e05aedd, 0x3708a5d3, 0x2c1fb8c1, 0x2512b3cf, 0x1a3182e5, 0x133c89eb, 0x082b94f9, 0x01269ff7, 0xe6bd464d, 0xefb04d43, 0xf4a75051, 0xfdaa5b5f, 0xc2896a75, 0xcb84617b, 0xd0937c69, 0xd99e7767, 0xaed51e3d, 0xa7d81533, 0xbccf0821, 0xb5c2032f, 0x8ae13205, 0x83ec390b, 0x98fb2419, 0x91f62f17, 0x4dd68d76, 0x44db8678, 0x5fcc9b6a, 0x56c19064, 0x69e2a14e, 0x60efaa40, 0x7bf8b752, 0x72f5bc5c, 0x05bed506, 0x0cb3de08, 0x17a4c31a, 0x1ea9c814, 0x218af93e, 0x2887f230, 0x3390ef22, 0x3a9de42c, 0xdd063d96, 0xd40b3698, 0xcf1c2b8a, 0xc6112084, 0xf93211ae, 0xf03f1aa0, 0xeb2807b2, 0xe2250cbc, 0x956e65e6, 0x9c636ee8, 0x877473fa, 0x8e7978f4, 0xb15a49de, 0xb85742d0, 0xa3405fc2, 0xaa4d54cc, 0xecdaf741, 0xe5d7fc4f, 0xfec0e15d, 0xf7cdea53, 0xc8eedb79, 0xc1e3d077, 0xdaf4cd65, 0xd3f9c66b, 0xa4b2af31, 0xadbfa43f, 0xb6a8b92d, 0xbfa5b223, 0x80868309, 0x898b8807, 0x929c9515, 0x9b919e1b, 0x7c0a47a1, 0x75074caf, 0x6e1051bd, 0x671d5ab3, 0x583e6b99, 0x51336097, 0x4a247d85, 0x4329768b, 0x34621fd1, 0x3d6f14df, 0x267809cd, 0x2f7502c3, 0x105633e9, 0x195b38e7, 0x024c25f5, 0x0b412efb, 0xd7618c9a, 0xde6c8794, 0xc57b9a86, 0xcc769188, 0xf355a0a2, 0xfa58abac, 0xe14fb6be, 0xe842bdb0, 0x9f09d4ea, 0x9604dfe4, 0x8d13c2f6, 0x841ec9f8, 0xbb3df8d2, 0xb230f3dc, 0xa927eece, 0xa02ae5c0, 0x47b13c7a, 0x4ebc3774, 0x55ab2a66, 0x5ca62168, 0x63851042, 0x6a881b4c, 0x719f065e, 0x78920d50, 0x0fd9640a, 0x06d46f04, 0x1dc37216, 0x14ce7918, 0x2bed4832, 0x22e0433c, 0x39f75e2e, 0x30fa5520, 0x9ab701ec, 0x93ba0ae2, 0x88ad17f0, 0x81a01cfe, 0xbe832dd4, 0xb78e26da, 0xac993bc8, 0xa59430c6, 0xd2df599c, 0xdbd25292, 0xc0c54f80, 0xc9c8448e, 0xf6eb75a4, 0xffe67eaa, 0xe4f163b8, 0xedfc68b6, 0x0a67b10c, 0x036aba02, 0x187da710, 0x1170ac1e, 0x2e539d34, 0x275e963a, 0x3c498b28, 0x35448026, 0x420fe97c, 0x4b02e272, 0x5015ff60, 0x5918f46e, 0x663bc544, 0x6f36ce4a, 0x7421d358, 0x7d2cd856, 0xa10c7a37, 0xa8017139, 0xb3166c2b, 0xba1b6725, 0x8538560f, 0x8c355d01, 0x97224013, 0x9e2f4b1d, 0xe9642247, 0xe0692949, 0xfb7e345b, 0xf2733f55, 0xcd500e7f, 0xc45d0571, 0xdf4a1863, 0xd647136d, 0x31dccad7, 0x38d1c1d9, 0x23c6dccb, 0x2acbd7c5, 0x15e8e6ef, 0x1ce5ede1, 0x07f2f0f3, 0x0efffbfd, 0x79b492a7, 0x70b999a9, 0x6bae84bb, 0x62a38fb5, 0x5d80be9f, 0x548db591, 0x4f9aa883, 0x4697a38d ];
|
||||
const sm_S = [ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 ];
|
||||
const sm_rcon = [ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 ];
|
||||
|
||||
function createArray(length) {
|
||||
var arr = new Array(length || 0);
|
||||
var i = length;
|
||||
|
||||
if (arguments.length > 1) {
|
||||
var args = Array.prototype.slice.call(arguments, 1);
|
||||
while (i--) {
|
||||
arr[length - 1 - i] = createArray.apply(this, args);
|
||||
}
|
||||
}
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
exports.HLEncoder = class HLEncoder {
|
||||
constructor(password) {
|
||||
this.kd = createArray(MAX_ROUNDS + 1, MAX_KC);
|
||||
this.ke = createArray(MAX_ROUNDS + 1, MAX_KC);
|
||||
this.tk = new Array(MAX_KC);
|
||||
|
||||
this.bKeyInit = false;
|
||||
this.iROUNDS = 0;
|
||||
|
||||
if (password) {
|
||||
var charCodes = new Array(password.length);
|
||||
for (var i = 0; i < password.length; i++) {
|
||||
charCodes[i] = password.charCodeAt(i);
|
||||
}
|
||||
this.makeKey(charCodes);
|
||||
}
|
||||
}
|
||||
|
||||
getEncryptedPassword(cls) {
|
||||
if (cls) {
|
||||
var charCodes = new Array(cls.length);
|
||||
for (var i = 0; i < cls.length; i++) {
|
||||
charCodes[i] = cls.charCodeAt(i);
|
||||
}
|
||||
return this.encrypt(charCodes);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
makeKey(sChallengeStr) {
|
||||
this.makeKeyFromBlock(this.makeBlock(sChallengeStr, 0));
|
||||
}
|
||||
|
||||
makeBlock(str, byFill) {
|
||||
var iLen = BLOCK_SIZE;
|
||||
if (str.length >= BLOCK_SIZE) {
|
||||
iLen = str.length;
|
||||
}
|
||||
var block = new Array((Math.floor(iLen / BLOCK_SIZE) + (iLen % BLOCK_SIZE > 0 ? 1 : 0)) * BLOCK_SIZE);
|
||||
for (var i = 0; i < block.length; i++) {
|
||||
if (i < str.length) {
|
||||
block[i] = str[i];
|
||||
} else {
|
||||
block[i] = byFill;
|
||||
}
|
||||
}
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
makeKeyFromBlock(block) {
|
||||
if (!block) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (block.length === 16 || block.length === 24 || block.length === 32) {
|
||||
switch (block.length) {
|
||||
case 16:
|
||||
this.iROUNDS = 10;
|
||||
break;
|
||||
case 24:
|
||||
this.iROUNDS = 12;
|
||||
break;
|
||||
default:
|
||||
this.iROUNDS = MAX_ROUNDS;
|
||||
break;
|
||||
}
|
||||
|
||||
for (var round = 0; round <= this.iROUNDS; round++) {
|
||||
for (var i = 0; i < 4; i++) {
|
||||
this.ke[round][i] = 0;
|
||||
this.kd[round][i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
var ROUND_KEY_COUNT = (this.iROUNDS + 1) * 4;
|
||||
var numBlockChunks = Math.floor(block.length / 4);
|
||||
for (var blockChunk = 0; blockChunk < numBlockChunks; blockChunk++) {
|
||||
this.tk[blockChunk] = ((block[(blockChunk * 4) + 0] << 24) | (block[(blockChunk * 4) + 1] << 16) | (block[(blockChunk * 4) + 2] << 8) | block[(blockChunk * 4) + 3]);
|
||||
}
|
||||
|
||||
var roundKey = 0;
|
||||
for (i = 0; i < numBlockChunks && roundKey < ROUND_KEY_COUNT; i++, roundKey++) {
|
||||
this.ke[Math.floor(roundKey / 4)][roundKey % 4] = this.tk[i];
|
||||
this.kd[this.iROUNDS - Math.floor(roundKey / 4)][roundKey % 4] = this.tk[i];
|
||||
}
|
||||
|
||||
for (var rconPointer = 0; roundKey < ROUND_KEY_COUNT; rconPointer++) {
|
||||
var tkVal = this.tk[numBlockChunks - 1];
|
||||
this.tk[0] ^= (((((sm_S[(tkVal >> 16) & 0xFF] << 24) ^ (sm_S[(tkVal >> 8) & 0xFF] << 16)) ^ (sm_S[tkVal & 0xFF] << 8)) ^ sm_S[(tkVal >> 24) & 0xFF]) ^ (sm_rcon[rconPointer] << 24));
|
||||
|
||||
if (numBlockChunks !== MAX_KC) {
|
||||
for (var prevIdx = 0, tkIdx = 1; tkIdx < numBlockChunks; prevIdx++, tkIdx++) {
|
||||
this.tk[tkIdx] ^= this.tk[prevIdx];
|
||||
}
|
||||
} else {
|
||||
var blockChunkMidpoint = Math.floor(numBlockChunks / 2);
|
||||
for (prevIdx = 0, tkIdx = 1; tkIdx < blockChunkMidpoint; prevIdx++, tkIdx++) {
|
||||
this.tk[tkIdx] ^= this.tk[prevIdx];
|
||||
}
|
||||
|
||||
tkVal = this.tk[blockChunkMidpoint - 1];
|
||||
this.tk[blockChunkMidpoint] ^= (((sm_S[tkVal & 0xFF] ^ (sm_S[(tkVal >> 8) & 0xFF] << 8)) ^ (sm_S[(tkVal >> 16) & 0xFF] << 16)) ^ (sm_S[(tkVal >> 24) & 0xFF] << 24));
|
||||
for (prevIdx = blockChunkMidpoint, tkIdx = blockChunkMidpoint + 1; tkIdx < numBlockChunks; prevIdx++, tkIdx++) {
|
||||
this.tk[tkIdx] ^= this.tk[prevIdx];
|
||||
}
|
||||
}
|
||||
|
||||
for (tkIdx = 0; tkIdx < numBlockChunks && roundKey < ROUND_KEY_COUNT; tkIdx++, roundKey++) {
|
||||
this.ke[Math.floor(roundKey / 4)][roundKey % 4] = this.tk[tkIdx];
|
||||
this.kd[this.iROUNDS - Math.floor(roundKey / 4)][roundKey % 4] = this.tk[tkIdx];
|
||||
}
|
||||
}
|
||||
|
||||
for (round = 1; round < this.iROUNDS; round++) {
|
||||
for (i = 0; i < 4; i++) {
|
||||
var tt = this.kd[round][i];
|
||||
this.kd[round][i] = ((sm_U1[(tt >> 24) & 0xFF] ^ sm_U2[(tt >> 16) & 0xFF]) ^ sm_U3[(tt >> 8) & 0xFF]) ^ sm_U4[tt & 0xFF];
|
||||
}
|
||||
}
|
||||
|
||||
this.bKeyInit = true;
|
||||
}
|
||||
}
|
||||
|
||||
encryptBlock(block) {
|
||||
if (!this.bKeyInit) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var a = (block[0] << 24 | block[1] << 16 | block[2] << 8 | block[3]) ^ this.ke[0][0];
|
||||
var b = (block[4] << 24 | block[5] << 16 | block[6] << 8 | block[7]) ^ this.ke[0][1];
|
||||
var c = (block[8] << 24 | block[9] << 16 | block[10] << 8 | block[11]) ^ this.ke[0][2];
|
||||
var d = (block[12] << 24 | block[13] << 16 | block[14] << 8 | block[15]) ^ this.ke[0][3];
|
||||
for (var round = 1; round < this.iROUNDS; round++) {
|
||||
var a1 = sm_T1[(a >> 24 & 0xFF)] ^ sm_T2[(b >> 16 & 0xFF)] ^ sm_T3[(c >> 8 & 0xFF)] ^ sm_T4[(d & 0xFF)] ^ this.ke[round][0];
|
||||
var b1 = sm_T1[(b >> 24 & 0xFF)] ^ sm_T2[(c >> 16 & 0xFF)] ^ sm_T3[(d >> 8 & 0xFF)] ^ sm_T4[(a & 0xFF)] ^ this.ke[round][1];
|
||||
var c1 = sm_T1[(c >> 24 & 0xFF)] ^ sm_T2[(d >> 16 & 0xFF)] ^ sm_T3[(a >> 8 & 0xFF)] ^ sm_T4[(b & 0xFF)] ^ this.ke[round][2];
|
||||
var d1 = sm_T1[(d >> 24 & 0xFF)] ^ sm_T2[(a >> 16 & 0xFF)] ^ sm_T3[(b >> 8 & 0xFF)] ^ sm_T4[(c & 0xFF)] ^ this.ke[round][3];
|
||||
|
||||
a = a1;
|
||||
b = b1;
|
||||
c = c1;
|
||||
d = d1;
|
||||
}
|
||||
|
||||
return [
|
||||
(sm_S[(a >> 24 & 0xFF)] ^ this.ke[this.iROUNDS][0] >> 24), (sm_S[(b >> 16 & 0xFF)] ^ this.ke[this.iROUNDS][0] >> 16), (sm_S[(c >> 8 & 0xFF)] ^ this.ke[this.iROUNDS][0] >> 8), (sm_S[(d & 0xFF)] ^ this.ke[this.iROUNDS][0]),
|
||||
(sm_S[(b >> 24 & 0xFF)] ^ this.ke[this.iROUNDS][1] >> 24), (sm_S[(c >> 16 & 0xFF)] ^ this.ke[this.iROUNDS][1] >> 16), (sm_S[(d >> 8 & 0xFF)] ^ this.ke[this.iROUNDS][1] >> 8), (sm_S[(a & 0xFF)] ^ this.ke[this.iROUNDS][1]),
|
||||
(sm_S[(c >> 24 & 0xFF)] ^ this.ke[this.iROUNDS][2] >> 24), (sm_S[(d >> 16 & 0xFF)] ^ this.ke[this.iROUNDS][2] >> 16), (sm_S[(a >> 8 & 0xFF)] ^ this.ke[this.iROUNDS][2] >> 8), (sm_S[(b & 0xFF)] ^ this.ke[this.iROUNDS][2]),
|
||||
(sm_S[(d >> 24 & 0xFF)] ^ this.ke[this.iROUNDS][3] >> 24), (sm_S[(a >> 16 & 0xFF)] ^ this.ke[this.iROUNDS][3] >> 16), (sm_S[(b >> 8 & 0xFF)] ^ this.ke[this.iROUNDS][3] >> 8), (sm_S[(c & 0xFF)] ^ this.ke[this.iROUNDS][3]),
|
||||
];
|
||||
}
|
||||
|
||||
encrypt(source) {
|
||||
if (this.bKeyInit) {
|
||||
return this.encryptData(this.makeBlock(source, 0));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
encryptData(data) {
|
||||
if (data == null || data.length < BLOCK_SIZE || data.length % BLOCK_SIZE !== 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var byEncrypted = Buffer.alloc(data.length);
|
||||
var iNBlocks = Math.floor(data.length / BLOCK_SIZE);
|
||||
for (var iBlock = 0; iBlock < iNBlocks; iBlock++) {
|
||||
var encryptedBlock = this.encryptBlock(data.slice(iBlock * BLOCK_SIZE, BLOCK_SIZE));
|
||||
for (var i = 0; i < encryptedBlock.length; i++) {
|
||||
byEncrypted[(iBlock * BLOCK_SIZE) + i] = encryptedBlock[i];
|
||||
}
|
||||
}
|
||||
return byEncrypted;
|
||||
}
|
||||
};
|
264
README.md
264
README.md
@ -1,8 +1,8 @@
|
||||
# node-screenlogic
|
||||
|
||||
This is a Node.JS library for interfacing with Pentair ScreenLogic systems over your local network. It requires a Pentair ScreenLogic device on the same network (a network which supports UDP broadcasts).
|
||||
This is a Node.JS library for interfacing with Pentair ScreenLogic systems over your local network or remotely through the Pentair dispatcher. Local connections require a Pentair ScreenLogic device on the same network (a network which supports UDP broadcasts).
|
||||
|
||||
Tested on node v8.11.1 with a system on firmware version 5.2 Build 736.0 Rel
|
||||
Tested on node v8.11.1, v10.15.1 with a system on firmware versions 5.2 Build 736.0 Rel, 5.2 Build 738.0 Rel
|
||||
|
||||
# Usage
|
||||
|
||||
@ -12,7 +12,7 @@ See example.js for an example of interfacing with the library. Broadly, import t
|
||||
const ScreenLogic = require('node-screenlogic');
|
||||
```
|
||||
|
||||
then create a new ScreenLogic unit finder with
|
||||
then for local connections create a new ScreenLogic unit finder with
|
||||
|
||||
```javascript
|
||||
new ScreenLogic.FindUnits();
|
||||
@ -26,12 +26,33 @@ Hook its `serverFound` event with
|
||||
|
||||
and call it via `search()`. This performs a UDP broadcast on 255.255.255.255, port 1444, so ensure your network supports UDP broadcasts and the device is on the same subnet.
|
||||
|
||||
When a server is found, create a new UnitConnection with
|
||||
Alternatively, to find a unit remotely, create a new ScreenLogic remote login with
|
||||
|
||||
```javascript
|
||||
new ScreenLogic.RemoteLogin('Pentair: xx-xx-xx')
|
||||
```
|
||||
|
||||
Hook its `gatewayFound` event with
|
||||
|
||||
```javascript
|
||||
.on('gatewayFound', function(unit) { })
|
||||
```
|
||||
|
||||
and call it via `connect()`. This opens a TCP connection to screenlogicserver.pentair.com, port 500.
|
||||
|
||||
When a local or remote server is found, create a new UnitConnection with
|
||||
|
||||
```javascript
|
||||
new ScreenLogic.UnitConnection(server);
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```javascript
|
||||
new ScreenLogic.UnitConnection(unit.port, unit.ipAddr, '1234')
|
||||
```
|
||||
where `'1234'` is the remote login password.
|
||||
|
||||
Once you've connected with `connect()`, there are a number of methods available and corresponding events for when they've completed successfully. See [UnitConnection](#unitconnection) API reference.
|
||||
|
||||
All communication with a ScreenLogic unit is done via TCP, so responses will come back in the order they were requested.
|
||||
@ -78,6 +99,34 @@ finder.on('serverFound', function(server) {
|
||||
})
|
||||
```
|
||||
|
||||
* `error` - Indicates that an unhandled error was caught (such as the connection timing out)
|
||||
|
||||
## RemoteLogin
|
||||
|
||||
### constructor(systemName)
|
||||
|
||||
Argument is the name of a system to connect to in "Pentair: xx-xx-xx" format.
|
||||
|
||||
Example:
|
||||
```javascript
|
||||
const ScreenLogic = require('./index');
|
||||
|
||||
var remoteLogin = new ScreenLogic.RemoteLogin('Pentair: xx-xx-xx');
|
||||
```
|
||||
|
||||
### connect()
|
||||
|
||||
Connects to the dispatcher service and searches for the unit passed to its constructor.
|
||||
|
||||
### close()
|
||||
|
||||
Closes the connection
|
||||
|
||||
### Events
|
||||
|
||||
* `gatewayFound` - Indicates that the search for the named unit has completed (may or may not be successful). Event handler receives a [`SLGetGatewayDataMessage`](#slgetgatewaydatamessage) argument.
|
||||
* `error` - Indicates that an unhandled error was caught (such as the connection timing out)
|
||||
|
||||
## UnitConnection
|
||||
|
||||
### constructor(server)
|
||||
@ -91,13 +140,21 @@ finder.on('serverFound', function(server) {
|
||||
})
|
||||
```
|
||||
|
||||
### constructor(port, address)
|
||||
```javascript
|
||||
remoteLogin.on('gatewayFound', function(unit) {
|
||||
if (unit && unit.gatewayFound) {
|
||||
var client = new ScreenLogic.UnitConnection(unit.port, unit.ipAddr, '1234'));
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
Port is an integer. Address is an IPv4 address of the server as a string.
|
||||
### constructor(port, address, password)
|
||||
|
||||
Port is an integer. Address is an IPv4 address of the server as a string. Password is optional; should be the 4-digit password in string form, e.g. `'1234'`.
|
||||
|
||||
Examples:
|
||||
```javascript
|
||||
var client = new ScreenLogic.UnitConnection(80, '10.0.0.85')
|
||||
var client = new ScreenLogic.UnitConnection(80, '10.0.0.85', '1234')
|
||||
```
|
||||
|
||||
### connect()
|
||||
@ -138,6 +195,24 @@ Requests controller configuration from the connected unit. Emits the `controller
|
||||
|
||||
Activates or deactivates a circuit. See [`SLSetCircuitStateMessage`](#slsetcircuitstatemessage) documentation for argument values. Emits the `circuitStateChanged` event when response is acknowledged.
|
||||
|
||||
### setSetPoint(controllerId, bodyType, temperature)
|
||||
|
||||
Sets the heating setpoint for any body. See [`SLSetHeatSetPointMessage`](#slsetheatsetpointmessage) documentation for argument values. Emits the `setPointChanged` event when response is acknowledged.
|
||||
|
||||
### setHeatMode(controllerId, bodyType, heatMode)
|
||||
|
||||
Sets the preferred heat mode. See [`SLSetHeatModeMessage`](#slsetheatmodemessage) documentation for argument values. Emits the `heatModeChanged` event when response is acknowledged.
|
||||
|
||||
### sendLightCommand(controllerId, command)
|
||||
|
||||
Sends a lighting command. See [`SLLightControlMessage`](#sllightcontrolmessage) documentation for argument values. Emits the `sentLightCommand` event when response is acknowledged.
|
||||
|
||||
Note that better/more complete handling of lighting is desired, but I have yet to find all the commands I need to implement to make that happen. This currently sends each command to all lights and there is no ability to send to an individual light. Pull requests adding more functionality here would be most welcome.
|
||||
|
||||
### setSaltCellOutput(controllerId, poolOutput, spaOutput)
|
||||
|
||||
Sets the salt cell's output levels. See [`SLSetSaltCellConfigMessage`](#slsetsaltcellconfigmessage) documentation for argument values. Emits the `setSaltCellConfig` event when response is acknowledged.
|
||||
|
||||
### Events
|
||||
|
||||
* `loggedIn` - Indicates that a connection to the server has been established and the login process completed. `get` methods can be called once this event has been emitted.
|
||||
@ -147,6 +222,18 @@ Activates or deactivates a circuit. See [`SLSetCircuitStateMessage`](#slsetcircu
|
||||
* `saltCellConfig` - Indicates that a response to `getSaltCellConfig()` has been received. Event handler receives a [`SLSaltCellConfigMessage`](#slsaltcellconfigmessage) object.
|
||||
* `controllerConfig` - Indicates that a response to `getControllerConfig()` has been received. Event handler receives a [`SLControllerConfigMessage`](#slcontrollerconfigmessage) object.
|
||||
* `circuitStateChanged` - Indicates that a response to `setCircuitState()` has been received. Event handler receives a [`SLSetCircuitStateMessage`](#slsetcircuitstatemessage) object.
|
||||
* `setPointChanged` - Indicates that a response to `setSetPoint()` has been received. Event handler receives a [`SLSetHeatSetPointMessage`](#slsetheatsetpointmessage) object.
|
||||
* `heatModeChanged` - Indicates that a response to `setHeatMode()` has been received. Event handler receives a [`SLSetHeatModeMessage`](#slsetheatmodemessage) object.
|
||||
* `sentLightCommand` - Indicates that a response to `sendLightCommand()` has been received. Event handler receives a [`SLLightControlMessage`](#sllightcontrolmessage) object.
|
||||
* `setSaltCellConfig` - Indicates that a response to `setSaltCellOutput()` has been received. Event handler receives a [`SLSetSaltCellConfigMessage`](#slsetsaltcellconfigmessage) object.
|
||||
* `loginFailed` - Indicates that a remote login attempt via supplying a system address and password to `UnitConnection` has failed likely due to the incorrect password being used.
|
||||
* `badParameter` - Indicates that a bad parameter has been supplied to a function. This can be triggered, for example, by sending the wrong controller ID to a `set` function.
|
||||
* `error` - Indicates that an unhandled error was caught (such as the connection timing out)
|
||||
* `addNewScheduleEvent` - will return a [`SLAddNewScheduleEvent`](#sladdnewscheduleevent) object. which contains the created `scheduleId` to be used later for setting up the properties
|
||||
* `deleteScheduleById` - Indicates a response to the `deleteScheduleById()` command has been received.
|
||||
* `getScheduleData` - will return a [`SLGetScheduleData`](#slgetscheduledata) object. which contains a list of events of the specified type
|
||||
* `setScheduleEventById` - Indicates a response to the `setScheduleEventById()` command has been received.
|
||||
* `setCircuitRuntimeById` - Indicates a response to the `setCircuitRuntimeById()` command has been received.
|
||||
|
||||
### Properties
|
||||
|
||||
@ -248,17 +335,48 @@ Passed as an argument to the emitted `saltCellConfig` event handler.
|
||||
### Properties
|
||||
|
||||
* `installed` - boolean indicating whether a salt cell is installed or not
|
||||
* `status` - integer
|
||||
* `level1` - integer
|
||||
* `level2` - integer
|
||||
* `status` - integer bitmask
|
||||
* `level1` - integer indicating the output level of the salt cell for the pool. I believe this operates on a 0-100 scale
|
||||
* `level2` - integer indicating the output level of the salt cell for the spa. I believe this operates on a 0-100 scale
|
||||
* `salt` - integer indicating salt level in parts-per-million
|
||||
* `flags` - integer
|
||||
* `flags` - integer bitmask
|
||||
* `superChlorTimer` - integer
|
||||
|
||||
## SLSetSaltCellConfigMessage
|
||||
|
||||
Passed as an argument to the emitted `setSaltCellConfig` event. The passed version is empty, however, since the response is just an acknowledgement of receipt of the set command.
|
||||
|
||||
### Properties
|
||||
|
||||
* `controllerId` - integer indicating the ID of the controller to send this command to.
|
||||
* Note that while `SLControllerConfigMessage` includes a controllerId, this ID, in my experience, should always be 0.
|
||||
* `poolOutput` - integer indicating the output level of the salt cell for the pool. I believe this operates on a 0-100 scale.
|
||||
* `spaOutput` - integer indicating the output level of the salt cell for the spa. I believe this operates on a 0-100 scale.
|
||||
|
||||
## SLControllerConfigMessage
|
||||
|
||||
Passed as an argument to the emitted `controllerConfig` event handler.
|
||||
|
||||
### hasSolar()
|
||||
|
||||
Returns a bool indicating whether the system has solar present. (Helper method for interpreting the value in `equipFlags`.)
|
||||
|
||||
### hasSolarAsHeatpump()
|
||||
|
||||
Returns a bool indicating whether the system has a solar heatpump (UltraTemp, ThermalFlo) present. (Helper method for interpreting the value in `equipFlags`.)
|
||||
|
||||
### hasChlorinator()
|
||||
|
||||
Returns a bool indicating whether the system has a chlorinator present. (Helper method for interpreting the value in `equipFlags`.)
|
||||
|
||||
### hasCooling()
|
||||
|
||||
Returns a bool indicating whether the system has a cooler present. (Helper method for interpreting the value in `equipFlags`.)
|
||||
|
||||
### hasIntellichem()
|
||||
|
||||
Returns a bool indicating whether the system has an IntelliChem chemical management system present. (Helper method for interpreting the value in `equipFlags`.)
|
||||
|
||||
### Properties
|
||||
|
||||
* `controllerId` - integer indicating the controller's ID
|
||||
@ -268,7 +386,7 @@ Passed as an argument to the emitted `controllerConfig` event handler.
|
||||
* `controllerType` - byte
|
||||
* `hwType` - byte
|
||||
* `controllerData` - byte
|
||||
* `equipFlags` - integer
|
||||
* `equipFlags` - integer indicating the type(s) of equipment present in the system (see helper methods above for interpreting these values)
|
||||
* `genCircuitName` - string indicating the circuit name
|
||||
* `bodyArray` - array (size number-of-circuits) holding circuit data
|
||||
* `circuitId` - integer indicating circuit ID (e.g.: 500 is spa, 505 is pool)
|
||||
@ -291,7 +409,7 @@ Passed as an argument to the emitted `controllerConfig` event handler.
|
||||
|
||||
## SLSetCircuitStateMessage
|
||||
|
||||
Passed as an argument to the emitted `circuitStateChanged`. The passed version is empty, however, since the response is just an acknowledgement of receipt of the set command.
|
||||
Passed as an argument to the emitted `circuitStateChanged` event. The passed version is empty, however, since the response is just an acknowledgement of receipt of the set command.
|
||||
|
||||
### Properties
|
||||
|
||||
@ -301,11 +419,119 @@ Passed as an argument to the emitted `circuitStateChanged`. The passed version i
|
||||
* This ID can be retrieved from `SLControllerConfigMessage`'s `bodyArray` property.
|
||||
* `circuitState` - integer indicating whether to switch the circuit on (`1`) or off (`0`).
|
||||
|
||||
# Changelog
|
||||
## SLSetHeatSetPointMessage
|
||||
|
||||
## v1.0.1
|
||||
* Added direct connection support.
|
||||
Passed as an argument to the emitted `setPointChanged` event. The passed version is empty, however, since the response is just an acknowledgement of receipt of the set command.
|
||||
|
||||
## v1.1.0
|
||||
* Added ability to set circuit state.
|
||||
* Fixed FindUnits.sendServerBroadcast() failing in certain environments.
|
||||
### Properties
|
||||
|
||||
* `controllerId` - integer indicating the ID of the controller to send this command to.
|
||||
* Note that while `SLControllerConfigMessage` includes a controllerId, this ID, in my experience, should always be 0.
|
||||
* `bodyType` - integer indicating the type of body to set the setpoint of. The pool is body `0` and the spa is body `1`.
|
||||
* `temperature` - integer indicating the desired setpoint. This is presumably in whatever units your system is set to (celsius or fahrenheit).
|
||||
|
||||
## SLSetHeatModeMessage
|
||||
|
||||
Passed as an argument to the emitted `heatModeChanged` event. The passed version is empty, however, since the response is just an acknowledgement of receipt of the set command.
|
||||
|
||||
### Properties
|
||||
|
||||
* `controllerId` - integer indicating the ID of the controller to send this command to.
|
||||
* Note that while `SLControllerConfigMessage` includes a controllerId, this ID, in my experience, should always be 0.
|
||||
* `bodyType` - integer indicating the type of body to set the setpoint of. The pool is body `0` and the spa is body `1`.
|
||||
* `heatMode` - integer indicating the desired heater mode. Valid values are: 0: "Off", 1: "Solar", 2 : "Solar Preferred", 3 : "Heat Pump", 4: "Don't Change"
|
||||
|
||||
## SLLightControlMessage
|
||||
|
||||
Passed as an argument to the emitted `sentLightCommand` event. The passed version is empty, however, since the response is just an acknowledgement of receipt of the light command.
|
||||
|
||||
### Properties
|
||||
|
||||
* `controllerId` - integer indicating the ID of the controller to send this command to.
|
||||
* Note that while `SLControllerConfigMessage` includes a controllerId, this ID, in my experience, should always be 0.
|
||||
* `command` - integer indicating which command to send to the lights. Valid values are:
|
||||
* ScreenLogic.LIGHT_CMD_LIGHTS_OFF
|
||||
* ScreenLogic.LIGHT_CMD_LIGHTS_ON
|
||||
* ScreenLogic.LIGHT_CMD_COLOR_SET
|
||||
* ScreenLogic.LIGHT_CMD_COLOR_SYNC
|
||||
* ScreenLogic.LIGHT_CMD_COLOR_SWIM
|
||||
* ScreenLogic.LIGHT_CMD_COLOR_MODE_PARTY
|
||||
* ScreenLogic.LIGHT_CMD_COLOR_MODE_ROMANCE
|
||||
* ScreenLogic.LIGHT_CMD_COLOR_MODE_CARIBBEAN
|
||||
* ScreenLogic.LIGHT_CMD_COLOR_MODE_AMERICAN
|
||||
* ScreenLogic.LIGHT_CMD_COLOR_MODE_SUNSET
|
||||
* ScreenLogic.LIGHT_CMD_COLOR_MODE_ROYAL
|
||||
* ScreenLogic.LIGHT_CMD_COLOR_SET_SAVE
|
||||
* ScreenLogic.LIGHT_CMD_COLOR_SET_RECALL
|
||||
* ScreenLogic.LIGHT_CMD_COLOR_BLUE
|
||||
* ScreenLogic.LIGHT_CMD_COLOR_GREEN
|
||||
* ScreenLogic.LIGHT_CMD_COLOR_RED
|
||||
* ScreenLogic.LIGHT_CMD_COLOR_WHITE
|
||||
* ScreenLogic.LIGHT_CMD_COLOR_PURPLE
|
||||
|
||||
## SLGetGatewayDataMessage
|
||||
|
||||
Passed as an argument to the emitted `gatewayFound` event. Contains information about the remote unit's status and access properties.
|
||||
|
||||
### Properties
|
||||
|
||||
* `gatewayFound` - boolean indicating whether a unit was found
|
||||
* `licenseOK` - boolean indicating if the license is valid (I've never seen this be false)
|
||||
* `ipAddr` - string containing the ipv4 address to remotely connect to this unit
|
||||
* `port` - number containing the port to connect to the unit
|
||||
* `portOpen` - boolean indicating whether or not the port is open and able to be connected to
|
||||
* `relayOn` - boolean indicating whether the relay is on (unsure what exactly this indicates; it's always been false in my tests)
|
||||
|
||||
## SLAddNewScheduleEvent
|
||||
|
||||
Adds a new event to the specified schedule type, either 0 for regular events or 1 for one-time events
|
||||
|
||||
### Properties
|
||||
|
||||
* `scheduleType` - 0 - indicates regular scheduled events, 1 - indicates a run-once event
|
||||
|
||||
## SLDeleteScheduleEventById
|
||||
|
||||
Deletes a scheduled event with specified id
|
||||
|
||||
### Properties
|
||||
|
||||
* `scheduleId` - the scheduleId of the schedule to be deleted
|
||||
|
||||
## SLGetScheduleData
|
||||
|
||||
Retrieves a list of schedule events of the specified type, either 0 for regular events or 1 for one-time events
|
||||
|
||||
### Properties
|
||||
|
||||
* `scheduleType` - 0 - indicates regular scheduled events, 1 - indicates a run-once event
|
||||
|
||||
## SLSetScheduleEventById
|
||||
|
||||
Configures an event with properties as described below
|
||||
|
||||
### Properties
|
||||
|
||||
* `scheduleId` - id of a schedule previously created, see [`SLAddNewScheduleEvent`](#sladdnewscheduleevent)
|
||||
* `circuitId` - id of the circuit to which this event applies to
|
||||
* `startTime` - the start time of the event, specified as minutes since midnight
|
||||
* example: 6:00am would be 360
|
||||
* example: 6:15am would be 375
|
||||
* `stopTime` - the stop time of the event, specified as minutes since midnight, format is the same as startTime
|
||||
* `dayMask`
|
||||
* 7-bit mask that determines which days the schedule is active for, MSB is always 0, valid numbers 1-127
|
||||
* `flags`
|
||||
* bit 0 is the schedule type, if 0 then regular event, if 1 its a run-once
|
||||
* bit 1 indicates whether heat setPoint should be changed
|
||||
* only valid values i've seen are 0,1,2,3
|
||||
* `heatCmd` - integer indicating the desired heater mode. Valid values are: 0: "Off", 1: "Solar", 2 : "Solar Preferred", 3 : "Heat Pump", 4: "Don't Change"
|
||||
* `heatSetPoint` - the temperature set point if heat is to be changed (ignored if bit 1 of flags is 0)
|
||||
|
||||
## SLSetCircuitRuntimeById
|
||||
|
||||
Configures default run-time of a circuit, usually referred to as the 'egg timer', this also applies to 'run-once' programs as this will set the length of the program
|
||||
|
||||
### Properties
|
||||
|
||||
* `circuitId` - id of the circuit to which this event applies to
|
||||
* `runTime` - integer specifying the minutes of runTime
|
67
example.js
67
example.js
@ -1,41 +1,66 @@
|
||||
'use strict';
|
||||
|
||||
const ScreenLogic = require('./index');
|
||||
|
||||
var finder = new ScreenLogic.FindUnits();
|
||||
finder.on('serverFound', function(server) {
|
||||
finder.close();
|
||||
connect(new ScreenLogic.UnitConnection(server));
|
||||
// use this to find and connect to units local to the network this is running on
|
||||
// var finder = new ScreenLogic.FindUnits();
|
||||
// finder.on('serverFound', function(server) {
|
||||
// finder.close();
|
||||
// connect(new ScreenLogic.UnitConnection(server));
|
||||
// });
|
||||
//
|
||||
// finder.search();
|
||||
|
||||
// use this if you want to use a direct connection to a known unit
|
||||
// connect(new ScreenLogic.UnitConnection(80, '10.0.0.85'));
|
||||
|
||||
// use this to remote connect to a system by name (going through the Pentair servers)
|
||||
const systemName = 'Pentair: xx-xx-xx';
|
||||
const password = '1234';
|
||||
|
||||
var remote = new ScreenLogic.RemoteLogin(systemName);
|
||||
remote.on('gatewayFound', function(unit) {
|
||||
remote.close();
|
||||
if (unit && unit.gatewayFound) {
|
||||
console.log('unit ' + remote.systemName + ' found at ' + unit.ipAddr + ':' + unit.port);
|
||||
connect(new ScreenLogic.UnitConnection(unit.port, unit.ipAddr, password));
|
||||
} else {
|
||||
console.log('no unit found by that name');
|
||||
}
|
||||
});
|
||||
|
||||
finder.search();
|
||||
|
||||
// use this instead of the above `finder` logic if you want to use a direct connection
|
||||
//connect(new ScreenLogic.UnitConnection(80, '10.0.0.85'));
|
||||
remote.connect();
|
||||
|
||||
// generic connection method used by all above examples
|
||||
function connect(client) {
|
||||
client.on('loggedIn', function() {
|
||||
this.getVersion();
|
||||
}).on('version', function(version) {
|
||||
this.getPoolStatus();
|
||||
console.log(" version=" + version.version);
|
||||
console.log(' version=' + version.version);
|
||||
}).on('poolStatus', function(status) {
|
||||
this.getChemicalData();
|
||||
console.log(" pool ok=" + status.ok);
|
||||
console.log(" air temp=" + status.airTemp);
|
||||
console.log(" salt ppm=" + status.saltPPM);
|
||||
console.log(" pH=" + status.pH);
|
||||
console.log(" saturation=" + status.saturation);
|
||||
console.log(" spa active=" + status.isSpaActive());
|
||||
console.log(" pool active=" + status.isPoolActive());
|
||||
console.log(' pool ok=' + status.ok);
|
||||
console.log(' pool temp=' + status.currentTemp[0]);
|
||||
console.log(' air temp=' + status.airTemp);
|
||||
console.log(' salt ppm=' + status.saltPPM);
|
||||
console.log(' pH=' + status.pH);
|
||||
console.log(' saturation=' + status.saturation);
|
||||
console.log(' spa active=' + status.isSpaActive());
|
||||
console.log(' pool active=' + status.isPoolActive());
|
||||
}).on('chemicalData', function(chemData) {
|
||||
this.getSaltCellConfig();
|
||||
console.log(" calcium=" + chemData.calcium);
|
||||
console.log(" cyanuric acid=" + chemData.cyanuricAcid);
|
||||
console.log(" alkalinity=" + chemData.alkalinity);
|
||||
console.log(' calcium=' + chemData.calcium);
|
||||
console.log(' cyanuric acid=' + chemData.cyanuricAcid);
|
||||
console.log(' alkalinity=' + chemData.alkalinity);
|
||||
}).on('saltCellConfig', function(saltCellConfig) {
|
||||
this.getControllerConfig();
|
||||
console.log(" salt cell installed=" + saltCellConfig.installed);
|
||||
console.log(' salt cell installed=' + saltCellConfig.installed);
|
||||
}).on('controllerConfig', function(config) {
|
||||
console.log(" controller is in celsius=" + config.degC);
|
||||
console.log(' controller is in celsius=' + config.degC);
|
||||
client.close();
|
||||
}).on('loginFailed', function() {
|
||||
console.log(' unable to login (wrong password?)');
|
||||
client.close();
|
||||
});
|
||||
|
||||
|
49
heatmodetest.js
Executable file
49
heatmodetest.js
Executable file
@ -0,0 +1,49 @@
|
||||
'use strict';
|
||||
|
||||
const ScreenLogic = require('./index');
|
||||
|
||||
// use this to find and connect to units local to the network this is running on
|
||||
var finder = new ScreenLogic.FindUnits();
|
||||
finder.on('serverFound', function(server) {
|
||||
finder.close();
|
||||
connect(new ScreenLogic.UnitConnection(server));
|
||||
});
|
||||
|
||||
finder.search();
|
||||
|
||||
// use this if you want to use a direct connection to a known unit
|
||||
// connect(new ScreenLogic.UnitConnection(80, '10.0.0.85'));
|
||||
|
||||
// use this to remote connect to a system by name (going through the Pentair servers)
|
||||
// const systemName = 'Pentair: xx-xx-xx';
|
||||
// const password = '1234';
|
||||
|
||||
// var remote = new ScreenLogic.RemoteLogin(systemName);
|
||||
// remote.on('gatewayFound', function(unit) {
|
||||
// remote.close();
|
||||
// if (unit && unit.gatewayFound) {
|
||||
// console.log('unit ' + remote.systemName + ' found at ' + unit.ipAddr + ':' + unit.port);
|
||||
// connect(new ScreenLogic.UnitConnection(unit.port, unit.ipAddr, password));
|
||||
// } else {
|
||||
// console.log('no unit found by that name');
|
||||
// }
|
||||
// });
|
||||
|
||||
// remote.connect();
|
||||
|
||||
// generic connection method used by all above examples
|
||||
function connect(client) {
|
||||
client.on('loggedIn', function() {
|
||||
this.getVersion();
|
||||
}).on('version', function(version) {
|
||||
this.setHeatMode(0, 0, 3);
|
||||
console.log(' version=' + version.version);
|
||||
}).on('heatModeChanged', function() {
|
||||
client.close();
|
||||
}).on('loginFailed', function() {
|
||||
console.log(' unable to login (wrong password?)');
|
||||
client.close();
|
||||
});
|
||||
|
||||
client.connect();
|
||||
}
|
250
index.js
250
index.js
@ -1,17 +1,22 @@
|
||||
'use strict';
|
||||
|
||||
var dgram = require('dgram');
|
||||
var net = require('net');
|
||||
const EventEmitter = require('events');
|
||||
const messages = require('./messages');
|
||||
const Encoder = require('./PasswordEncoder').HLEncoder;
|
||||
|
||||
class FindUnits extends EventEmitter {
|
||||
constructor() {
|
||||
super();
|
||||
this.finder = dgram.createSocket('udp4');
|
||||
var _this = this;
|
||||
this.finder.on('message', function (message, remote) {
|
||||
this.finder.on('message', function(message, remote) {
|
||||
_this.foundServer(message, remote);
|
||||
}).on('close', function() {
|
||||
//console.log('finder closed');
|
||||
// console.log('finder closed');
|
||||
}).on('error', function(e) {
|
||||
_this.emit('error', e);
|
||||
});
|
||||
}
|
||||
|
||||
@ -25,7 +30,7 @@ class FindUnits extends EventEmitter {
|
||||
}
|
||||
|
||||
foundServer(message, remote) {
|
||||
//console.log('Found something');
|
||||
// console.log('Found something');
|
||||
if (message.length >= 40) {
|
||||
var server = {
|
||||
address: remote.address,
|
||||
@ -33,10 +38,11 @@ class FindUnits extends EventEmitter {
|
||||
port: message.readInt16LE(8),
|
||||
gatewayType: message.readUInt8(10),
|
||||
gatewaySubtype: message.readUInt8(11),
|
||||
gatewayName: message.toString('utf8', 12, 28)
|
||||
gatewayName: message.toString('utf8', 12, 29),
|
||||
};
|
||||
|
||||
//console.log(' type: ' + server.type + ', host: ' + server.address + ':' + server.port + ', identified as ' + server.gatewayName);
|
||||
// console.log(' type: ' + server.type + ', host: ' + server.address + ':' + server.port + ',
|
||||
// identified as ' + server.gatewayName);
|
||||
if (server.type === 2) {
|
||||
this.emit('serverFound', server);
|
||||
}
|
||||
@ -46,8 +52,8 @@ class FindUnits extends EventEmitter {
|
||||
sendServerBroadcast() {
|
||||
var message = Buffer.alloc(8);
|
||||
message[0] = 1;
|
||||
this.finder.send(message, 0, message.length, 1444, "255.255.255.255");
|
||||
//console.log("Looking for ScreenLogic hosts...");
|
||||
this.finder.send(message, 0, message.length, 1444, '255.255.255.255');
|
||||
// console.log("Looking for ScreenLogic hosts...");
|
||||
}
|
||||
|
||||
close() {
|
||||
@ -55,8 +61,61 @@ class FindUnits extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
class RemoteLogin extends EventEmitter {
|
||||
constructor(systemName) {
|
||||
super();
|
||||
|
||||
this.systemName = systemName;
|
||||
this.client = new net.Socket();
|
||||
var _this = this;
|
||||
this.client.on('data', function(msg) {
|
||||
_this.onClientMessage(msg);
|
||||
}).on('close', function(had_error) {
|
||||
// console.log('remote login server connection closed');
|
||||
}).on('error', function(e) {
|
||||
_this.emit('error', e);
|
||||
});
|
||||
}
|
||||
|
||||
connect() {
|
||||
// console.log('connecting to dispatcher...');
|
||||
var _this = this;
|
||||
this.client.connect(500, 'screenlogicserver.pentair.com', function() {
|
||||
_this.onConnected();
|
||||
});
|
||||
}
|
||||
|
||||
onConnected() {
|
||||
// console.log('connected to dispatcher');
|
||||
|
||||
this.client.write(new messages.SLGetGatewayDataMessage(this.systemName).toBuffer());
|
||||
}
|
||||
|
||||
onClientMessage(msg) {
|
||||
// console.log('received message of length ' + msg.length);
|
||||
if (msg.length < 4) {
|
||||
return;
|
||||
}
|
||||
|
||||
var msgType = msg.readInt16LE(2);
|
||||
switch (msgType) {
|
||||
case messages.SLGetGatewayDataMessage.getResponseId():
|
||||
// console.log(" it's a gateway response");
|
||||
this.emit('gatewayFound', new messages.SLGetGatewayDataMessage(msg));
|
||||
break;
|
||||
default:
|
||||
// console.log(" it's unknown. type: " + msgType);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
close() {
|
||||
this.client.end();
|
||||
}
|
||||
}
|
||||
|
||||
class UnitConnection extends EventEmitter {
|
||||
constructor(server, address) {
|
||||
constructor(server, address, password) {
|
||||
super();
|
||||
if (typeof server === 'object') {
|
||||
this.serverPort = server.port;
|
||||
@ -66,12 +125,33 @@ class UnitConnection extends EventEmitter {
|
||||
this.serverAddress = address;
|
||||
}
|
||||
|
||||
this.password = password;
|
||||
this.client = new net.Socket();
|
||||
var _this = this;
|
||||
var buffer = Buffer.alloc(1024);
|
||||
var bufferIdx = 0;
|
||||
var expectedMsgLen = 0;
|
||||
|
||||
this.client.on('data', function(msg) {
|
||||
_this.onClientMessage(msg);
|
||||
if (buffer.length < msg.length + bufferIdx) {
|
||||
buffer = Buffer.alloc(msg.length + buffer.length, buffer);
|
||||
}
|
||||
|
||||
if (bufferIdx === 0) {
|
||||
expectedMsgLen = msg.readInt32LE(4) + 8;
|
||||
}
|
||||
|
||||
msg.copy(buffer, bufferIdx);
|
||||
bufferIdx = bufferIdx + msg.length;
|
||||
|
||||
if (bufferIdx === expectedMsgLen) {
|
||||
_this.onClientMessage(buffer.slice(0, expectedMsgLen));
|
||||
bufferIdx = 0;
|
||||
}
|
||||
}).on('close', function(had_error) {
|
||||
//console.log('unit connection closed');
|
||||
// console.log('unit connection closed');
|
||||
}).on('error', function(e) {
|
||||
_this.emit('error', e);
|
||||
});
|
||||
}
|
||||
|
||||
@ -80,7 +160,7 @@ class UnitConnection extends EventEmitter {
|
||||
}
|
||||
|
||||
connect() {
|
||||
//console.log("connecting...");
|
||||
// console.log("connecting...");
|
||||
var _this = this;
|
||||
this.client.connect(this.serverPort, this.serverAddress, function() {
|
||||
_this.onConnected();
|
||||
@ -88,51 +168,93 @@ class UnitConnection extends EventEmitter {
|
||||
}
|
||||
|
||||
onConnected() {
|
||||
//console.log('connected');
|
||||
// console.log('connected');
|
||||
|
||||
//console.log('sending init message...');
|
||||
// console.log('sending init message...');
|
||||
this.client.write('CONNECTSERVERHOST\r\n\r\n');
|
||||
|
||||
//console.log('sending challenge message...');
|
||||
// console.log('sending challenge message...');
|
||||
this.client.write(new messages.SLChallengeMessage().toBuffer());
|
||||
}
|
||||
|
||||
login() {
|
||||
//console.log('sending login message...');
|
||||
this.client.write(new messages.SLLoginMessage().toBuffer());
|
||||
// console.log('sending login message...');
|
||||
var password = new Encoder(this.password).getEncryptedPassword(this.challengeString);
|
||||
this.client.write(new messages.SLLoginMessage(password).toBuffer());
|
||||
}
|
||||
|
||||
getPoolStatus() {
|
||||
//console.log('sending pool status query...');
|
||||
// console.log('sending pool status query...');
|
||||
this.client.write(new messages.SLPoolStatusMessage().toBuffer());
|
||||
}
|
||||
|
||||
getControllerConfig() {
|
||||
//console.log('sending controller config query...');
|
||||
// console.log('sending controller config query...');
|
||||
this.client.write(new messages.SLControllerConfigMessage().toBuffer());
|
||||
}
|
||||
|
||||
getChemicalData() {
|
||||
//console.log('sending chemical data query...');
|
||||
// console.log('sending chemical data query...');
|
||||
this.client.write(new messages.SLChemDataMessage().toBuffer());
|
||||
}
|
||||
|
||||
getSaltCellConfig() {
|
||||
//console.log('sending salt cell config query...');
|
||||
// console.log('sending salt cell config query...');
|
||||
this.client.write(new messages.SLSaltCellConfigMessage().toBuffer());
|
||||
}
|
||||
|
||||
getVersion() {
|
||||
//console.log('sending version query...');
|
||||
// console.log('sending version query...');
|
||||
this.client.write(new messages.SLVersionMessage().toBuffer());
|
||||
}
|
||||
|
||||
getEquipmentConfiguration() {
|
||||
this.client.write(new messages.SLEquipmentConfigurationMessage().toBuffer());
|
||||
}
|
||||
|
||||
setCircuitState(controllerId, circuitId, circuitState) {
|
||||
this.client.write(new messages.SLSetCircuitStateMessage(controllerId, circuitId, circuitState).toBuffer());
|
||||
}
|
||||
|
||||
setSetPoint(controllerId, bodyType, temperature) {
|
||||
this.client.write(new messages.SLSetHeatSetPointMessage(controllerId, bodyType, temperature).toBuffer());
|
||||
}
|
||||
|
||||
setHeatMode(controllerId, bodyType, heatMode) {
|
||||
this.client.write(new messages.SLSetHeatModeMessage(controllerId, bodyType, heatMode).toBuffer());
|
||||
}
|
||||
|
||||
sendLightCommand(controllerId, command) {
|
||||
this.client.write(new messages.SLLightControlMessage(controllerId, command).toBuffer());
|
||||
}
|
||||
|
||||
setSaltCellOutput(controllerId, poolOutput, spaOutput) {
|
||||
this.client.write(new messages.SLSetSaltCellConfigMessage(controllerId, poolOutput, spaOutput).toBuffer());
|
||||
}
|
||||
|
||||
getScheduleData(scheduleType) {
|
||||
this.client.write(new messages.SLGetScheduleData(null, scheduleType).toBuffer());
|
||||
}
|
||||
|
||||
addNewScheduleEvent(scheduleType) {
|
||||
this.client.write(new messages.SLAddNewScheduleEvent(null, scheduleType).toBuffer());
|
||||
}
|
||||
|
||||
deleteScheduleEventById(scheduleId) {
|
||||
this.client.write(new messages.SLDeleteScheduleEventById(scheduleId).toBuffer());
|
||||
}
|
||||
|
||||
setScheduleEventById(scheduleId, circuitId, startTime, stopTime, dayMask, flags, heatCmd, heatSetPoint) {
|
||||
this.client.write(new messages.SLSetScheduleEventById(null, scheduleId, circuitId, startTime, stopTime,
|
||||
dayMask, flags, heatCmd, heatSetPoint).toBuffer());
|
||||
}
|
||||
|
||||
setCircuitRuntimebyId(circuitId, runTime) {
|
||||
this.client.write(new messages.SLSetCircuitRuntimeById(circuitId, runTime).toBuffer());
|
||||
}
|
||||
|
||||
onClientMessage(msg) {
|
||||
//console.log('received message of length ' + msg.length);
|
||||
// console.log('received message of length ' + msg.length);
|
||||
if (msg.length < 4) {
|
||||
return;
|
||||
}
|
||||
@ -140,39 +262,82 @@ class UnitConnection extends EventEmitter {
|
||||
var msgType = msg.readInt16LE(2);
|
||||
switch (msgType) {
|
||||
case messages.SLChallengeMessage.getResponseId():
|
||||
//console.log(" it's a challenge response");
|
||||
// console.log(" it's a challenge response");
|
||||
this.challengeString = new messages.SLChallengeMessage(msg).challengeString;
|
||||
this.login();
|
||||
break;
|
||||
case messages.SLLoginMessage.getResponseId():
|
||||
//console.log(" it's a login response");
|
||||
// console.log(" it's a login response");
|
||||
this.emit('loggedIn');
|
||||
break;
|
||||
case messages.SLPoolStatusMessage.getResponseId():
|
||||
//console.log(" it's pool status");
|
||||
// console.log(" it's pool status");
|
||||
this.emit('poolStatus', new messages.SLPoolStatusMessage(msg));
|
||||
break;
|
||||
case messages.SLControllerConfigMessage.getResponseId():
|
||||
//console.log(" it's controller configuration");
|
||||
// console.log(" it's controller configuration");
|
||||
this.emit('controllerConfig', new messages.SLControllerConfigMessage(msg));
|
||||
break;
|
||||
case messages.SLChemDataMessage.getResponseId():
|
||||
//console.log(" it's chem data");
|
||||
// console.log(" it's chem data");
|
||||
this.emit('chemicalData', new messages.SLChemDataMessage(msg));
|
||||
break;
|
||||
case messages.SLSaltCellConfigMessage.getResponseId():
|
||||
//console.log(" it's salt cell config");
|
||||
// console.log(" it's salt cell config");
|
||||
this.emit('saltCellConfig', new messages.SLSaltCellConfigMessage(msg));
|
||||
break;
|
||||
case messages.SLVersionMessage.getResponseId():
|
||||
//console.log(" it's version");
|
||||
// console.log(" it's version");
|
||||
this.emit('version', new messages.SLVersionMessage(msg));
|
||||
break;
|
||||
case messages.SLSetCircuitStateMessage.getResponseId():
|
||||
//console.log(" it's circuit toggle ack");
|
||||
// console.log(" it's circuit toggle ack");
|
||||
this.emit('circuitStateChanged', new messages.SLSetCircuitStateMessage());
|
||||
break;
|
||||
case messages.SLSetHeatSetPointMessage.getResponseId():
|
||||
// console.log(" it's a setpoint ack");
|
||||
this.emit('setPointChanged', new messages.SLSetHeatSetPointMessage());
|
||||
break;
|
||||
case messages.SLSetHeatModeMessage.getResponseId():
|
||||
// console.log(" it's a heater mode ack");
|
||||
this.emit('heatModeChanged', new messages.SLSetHeatModeMessage());
|
||||
break;
|
||||
case messages.SLLightControlMessage.getResponseId():
|
||||
// console.log(" it's a light control ack");
|
||||
this.emit('sentLightCommand', new messages.SLLightControlMessage());
|
||||
break;
|
||||
case messages.SLSetSaltCellConfigMessage.getResponseId():
|
||||
// console.log(" it's a set salt cell config ack");
|
||||
this.emit('setSaltCellConfig', new messages.SLSetSaltCellConfigMessage());
|
||||
break;
|
||||
case messages.SLEquipmentConfigurationMessage.getResponseId():
|
||||
this.emit('equipmentConfiguration', new messages.SLEquipmentConfigurationMessage(msg));
|
||||
break;
|
||||
case messages.SLGetScheduleData.getResponseId():
|
||||
this.emit('getScheduleData', new messages.SLGetScheduleData(msg));
|
||||
break;
|
||||
case messages.SLAddNewScheduleEvent.getResponseId():
|
||||
this.emit('addNewScheduleEvent', new messages.SLAddNewScheduleEvent(msg));
|
||||
break;
|
||||
case messages.SLDeleteScheduleEventById.getResponseId():
|
||||
this.emit('deleteScheduleEventById', new messages.SLDeleteScheduleEventById(msg));
|
||||
break;
|
||||
case messages.SLSetScheduleEventById.getResponseId():
|
||||
this.emit('setScheduleEventById', new messages.SLSetScheduleEventById(msg));
|
||||
break;
|
||||
case messages.SLSetCircuitRuntimeById.getResponseId():
|
||||
this.emit('setCircuitRuntimebyId', new messages.SLSetCircuitRuntimeById());
|
||||
break;
|
||||
case 13:
|
||||
// console.log(" it's a login failure.");
|
||||
this.emit('loginFailed');
|
||||
break;
|
||||
case 31:
|
||||
// console.log(" it's a parameter failure.");
|
||||
this.emit('badParameter');
|
||||
break;
|
||||
default:
|
||||
//console.log(" it's unknown. type: " + msgType);
|
||||
// console.log(" it's unknown. type: " + msgType);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -186,5 +351,24 @@ for (const value of buf.values()) {
|
||||
|
||||
module.exports = {
|
||||
FindUnits,
|
||||
UnitConnection
|
||||
}
|
||||
RemoteLogin,
|
||||
UnitConnection,
|
||||
LIGHT_CMD_LIGHTS_OFF: 0,
|
||||
LIGHT_CMD_LIGHTS_ON: 1,
|
||||
LIGHT_CMD_COLOR_SET: 2,
|
||||
LIGHT_CMD_COLOR_SYNC: 3,
|
||||
LIGHT_CMD_COLOR_SWIM: 4,
|
||||
LIGHT_CMD_COLOR_MODE_PARTY: 5,
|
||||
LIGHT_CMD_COLOR_MODE_ROMANCE: 6,
|
||||
LIGHT_CMD_COLOR_MODE_CARIBBEAN: 7,
|
||||
LIGHT_CMD_COLOR_MODE_AMERICAN: 8,
|
||||
LIGHT_CMD_COLOR_MODE_SUNSET: 9,
|
||||
LIGHT_CMD_COLOR_MODE_ROYAL: 10,
|
||||
LIGHT_CMD_COLOR_SET_SAVE: 11,
|
||||
LIGHT_CMD_COLOR_SET_RECALL: 12,
|
||||
LIGHT_CMD_COLOR_BLUE: 13,
|
||||
LIGHT_CMD_COLOR_GREEN: 14,
|
||||
LIGHT_CMD_COLOR_RED: 15,
|
||||
LIGHT_CMD_COLOR_WHITE: 16,
|
||||
LIGHT_CMD_COLOR_PURPLE: 17,
|
||||
};
|
||||
|
38
messages/SLAddNewScheduleEvent.js
Normal file
38
messages/SLAddNewScheduleEvent.js
Normal file
@ -0,0 +1,38 @@
|
||||
'use strict';
|
||||
|
||||
const SLMessage = require('./SLMessage.js').SLMessage;
|
||||
|
||||
const MSG_ID = 12544;
|
||||
|
||||
|
||||
exports.SLAddNewScheduleEvent = class SLAddNewScheduleEvent extends SLMessage {
|
||||
constructor(buf, scheduleType) {
|
||||
var size;
|
||||
if (buf) {
|
||||
size = buf.readInt32LE(4) + 8;
|
||||
}
|
||||
super(0, MSG_ID, size);
|
||||
|
||||
|
||||
if (!buf) {
|
||||
// console.log('Requested Schedule type = ', scheduleType);
|
||||
this.writeInt32LE(0);
|
||||
this.writeInt32LE(scheduleType);
|
||||
} else {
|
||||
this._wroteSize = true;
|
||||
this.writeBuffer(buf, 0);
|
||||
|
||||
this.decode();
|
||||
}
|
||||
}
|
||||
|
||||
decode() {
|
||||
super.decode();
|
||||
|
||||
this.scheduleId = this.readUInt32LE();
|
||||
}
|
||||
|
||||
static getResponseId() {
|
||||
return MSG_ID + 1;
|
||||
}
|
||||
};
|
@ -1,13 +1,32 @@
|
||||
'use strict';
|
||||
|
||||
const SLMessage = require('./SLMessage.js').SLMessage;
|
||||
|
||||
const MSG_ID = 14;
|
||||
|
||||
exports.SLChallengeMessage = class SLChallengeMessage extends SLMessage {
|
||||
constructor() {
|
||||
super(0, MSG_ID);
|
||||
constructor(buf) {
|
||||
var size;
|
||||
if (buf) {
|
||||
size = buf.readInt32LE(4) + 8;
|
||||
}
|
||||
super(0, MSG_ID, size);
|
||||
|
||||
if (buf) {
|
||||
this._wroteSize = true;
|
||||
this.writeBuffer(buf, 0);
|
||||
|
||||
this.decode();
|
||||
}
|
||||
}
|
||||
|
||||
decode() {
|
||||
super.decode();
|
||||
|
||||
this.challengeString = this.readSLString();
|
||||
}
|
||||
|
||||
static getResponseId() {
|
||||
return MSG_ID + 1;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -1,10 +1,17 @@
|
||||
'use strict';
|
||||
|
||||
const SLMessage = require('./SLMessage.js').SLMessage;
|
||||
|
||||
const MSG_ID = 12592;
|
||||
|
||||
exports.SLChemDataMessage = class SLChemDataMessage extends SLMessage {
|
||||
constructor(buf) {
|
||||
super(0, MSG_ID);
|
||||
var size;
|
||||
if (buf) {
|
||||
size = buf.readInt32LE(4) + 8;
|
||||
}
|
||||
super(0, MSG_ID, size);
|
||||
|
||||
if (!buf) {
|
||||
this.writeInt32LE(0); // controller index
|
||||
} else {
|
||||
@ -53,4 +60,4 @@ exports.SLChemDataMessage = class SLChemDataMessage extends SLMessage {
|
||||
static getResponseId() {
|
||||
return MSG_ID + 1;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -1,10 +1,17 @@
|
||||
'use strict';
|
||||
|
||||
const SLMessage = require('./SLMessage.js').SLMessage;
|
||||
|
||||
const MSG_ID = 12532;
|
||||
|
||||
exports.SLControllerConfigMessage = class SLControllerConfigMessage extends SLMessage {
|
||||
constructor(buf) {
|
||||
super(0, MSG_ID);
|
||||
var size;
|
||||
if (buf) {
|
||||
size = buf.readInt32LE(4) + 8;
|
||||
}
|
||||
super(0, MSG_ID, size);
|
||||
|
||||
if (!buf) {
|
||||
this.writeInt32LE(0);
|
||||
this.writeInt32LE(0);
|
||||
@ -49,8 +56,8 @@ exports.SLControllerConfigMessage = class SLControllerConfigMessage extends SLMe
|
||||
colorPos: this.readUInt8(),
|
||||
colorStagger: this.readUInt8(),
|
||||
deviceId: this.readUInt8(),
|
||||
dfaultRt: this.readUInt16LE()
|
||||
}
|
||||
dfaultRt: this.readUInt16LE(),
|
||||
};
|
||||
this._readOffset += 2;
|
||||
}
|
||||
|
||||
@ -60,11 +67,11 @@ exports.SLControllerConfigMessage = class SLControllerConfigMessage extends SLMe
|
||||
this.colorArray[i] = {
|
||||
name: this.readSLString(),
|
||||
color: {
|
||||
r: this.readInt32LE() & 0xFF,
|
||||
g: this.readInt32LE() & 0xFF,
|
||||
b: this.readInt32LE() & 0xFF
|
||||
}
|
||||
}
|
||||
r: this.readInt32LE() & 0xff,
|
||||
g: this.readInt32LE() & 0xff,
|
||||
b: this.readInt32LE() & 0xff,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
let pumpCircCount = 8;
|
||||
@ -80,4 +87,44 @@ exports.SLControllerConfigMessage = class SLControllerConfigMessage extends SLMe
|
||||
static getResponseId() {
|
||||
return MSG_ID + 1;
|
||||
}
|
||||
}
|
||||
|
||||
hasSolar() {
|
||||
return !!(this.equipFlags & 0x1);
|
||||
}
|
||||
|
||||
hasSolarAsHeatpump() {
|
||||
return !!(this.equipFlags & 0x2);
|
||||
}
|
||||
|
||||
hasChlorinator() {
|
||||
return !!(this.equipFlags & 0x4);
|
||||
}
|
||||
|
||||
hasCooling() {
|
||||
return !!(this.equipFlags & 0x800);
|
||||
}
|
||||
|
||||
hasIntellichem() {
|
||||
return !!(this.equipFlags & 0x8000);
|
||||
}
|
||||
|
||||
isEasyTouch() {
|
||||
return this.controllerType === 14 || this.controllerType === 13;
|
||||
}
|
||||
|
||||
isIntelliTouch() {
|
||||
return this.controllerType !== 14 && this.controllerType !== 13 && this.controllerType !== 10;
|
||||
}
|
||||
|
||||
isEasyTouchLite() {
|
||||
return this.controllerType === 13 && (this.hwType & 4) !== 0;
|
||||
}
|
||||
|
||||
isDualBody() {
|
||||
return this.controllerType === 5;
|
||||
}
|
||||
|
||||
isChem2() {
|
||||
return this.controllerType === 252 && this.hwType === 2;
|
||||
}
|
||||
};
|
||||
|
18
messages/SLDeleteScheduleEventById.js
Normal file
18
messages/SLDeleteScheduleEventById.js
Normal file
@ -0,0 +1,18 @@
|
||||
'use strict';
|
||||
|
||||
const SLMessage = require('./SLMessage.js').SLMessage;
|
||||
|
||||
const MSG_ID = 12546;
|
||||
|
||||
exports.SLDeleteScheduleEventById = class SLDeleteScheduleEventById extends SLMessage {
|
||||
constructor(scheduleId) {
|
||||
super(0, MSG_ID);
|
||||
|
||||
this.writeInt32LE(0);
|
||||
this.writeInt32LE(scheduleId);
|
||||
}
|
||||
|
||||
static getResponseId() {
|
||||
return MSG_ID + 1;
|
||||
}
|
||||
};
|
51
messages/SLEquipmentConfigurationMessage.js
Normal file
51
messages/SLEquipmentConfigurationMessage.js
Normal file
@ -0,0 +1,51 @@
|
||||
'use strict';
|
||||
|
||||
const SLMessage = require('./SLMessage.js').SLMessage;
|
||||
|
||||
const MSG_ID = 12566;
|
||||
|
||||
exports.SLEquipmentConfigurationMessage = class SLEquipmentConfigurationMessage extends SLMessage {
|
||||
constructor(buf) {
|
||||
var size;
|
||||
if (buf) {
|
||||
size = buf.readInt32LE(4) + 8;
|
||||
}
|
||||
super(0, MSG_ID, size);
|
||||
|
||||
if (!buf) {
|
||||
this.writeInt32LE(0);
|
||||
this.writeInt32LE(0);
|
||||
} else {
|
||||
this._wroteSize = true;
|
||||
this.writeBuffer(buf, 0);
|
||||
|
||||
this.decode();
|
||||
}
|
||||
}
|
||||
|
||||
decode() {
|
||||
super.decode();
|
||||
|
||||
this.controllerType = this.readUInt8();
|
||||
this.hardwareType = this.readUInt8();
|
||||
this.readUInt8();
|
||||
this.readUInt8();
|
||||
this.controllerData = this.readInt32LE();
|
||||
this.versionDataArray = this.readSLArray();
|
||||
this.speedDataArray = this.readSLArray();
|
||||
this.valveDataArray = this.readSLArray();
|
||||
this.remoteDataArray = this.readSLArray();
|
||||
this.sensorDataArray = this.readSLArray();
|
||||
this.delayDataArray = this.readSLArray();
|
||||
this.macroDataArray = this.readSLArray();
|
||||
this.miscDataArray = this.readSLArray();
|
||||
this.lightDataArray = this.readSLArray();
|
||||
this.flowDataArray = this.readSLArray();
|
||||
this.sgDataArray = this.readSLArray();
|
||||
this.spaFlowDataArray = this.readSLArray();
|
||||
}
|
||||
|
||||
static getResponseId() {
|
||||
return MSG_ID + 1;
|
||||
}
|
||||
};
|
40
messages/SLGetGatewayDataMessage.js
Normal file
40
messages/SLGetGatewayDataMessage.js
Normal file
@ -0,0 +1,40 @@
|
||||
'use strict';
|
||||
|
||||
const SLMessage = require('./SLMessage.js').SLMessage;
|
||||
|
||||
const MSG_ID = 18003;
|
||||
|
||||
exports.SLGetGatewayDataMessage = class SLGetGatewayDataMessage extends SLMessage {
|
||||
constructor(buf) {
|
||||
var size;
|
||||
if (buf && typeof buf === 'object') {
|
||||
size = buf.readInt32LE(4) + 8;
|
||||
}
|
||||
super(0, MSG_ID, size);
|
||||
|
||||
if (typeof buf === 'string') {
|
||||
this.writeSLString(buf);
|
||||
this.writeSLString(buf);
|
||||
} else if (buf) {
|
||||
this._wroteSize = true;
|
||||
this.writeBuffer(buf, 0);
|
||||
|
||||
this.decode();
|
||||
}
|
||||
}
|
||||
|
||||
decode() {
|
||||
super.decode();
|
||||
|
||||
this.gatewayFound = this.readUInt8() !== 0;
|
||||
this.licenseOK = this.readUInt8() !== 0;
|
||||
this.ipAddr = this.readSLString();
|
||||
this.port = this.readUInt16LE();
|
||||
this.portOpen = this.readUInt8() !== 0;
|
||||
this.relayOn = this.readUInt8() !== 0;
|
||||
}
|
||||
|
||||
static getResponseId() {
|
||||
return MSG_ID + 1;
|
||||
}
|
||||
};
|
63
messages/SLGetScheduleData.js
Normal file
63
messages/SLGetScheduleData.js
Normal file
@ -0,0 +1,63 @@
|
||||
'use strict';
|
||||
|
||||
const SLMessage = require('./SLMessage.js').SLMessage;
|
||||
|
||||
const MSG_ID = 12542;
|
||||
|
||||
exports.SLGetScheduleData = class SLGetScheduleData extends SLMessage {
|
||||
constructor(buf, scheduleType) {
|
||||
var size;
|
||||
if (buf) {
|
||||
size = buf.readInt32LE(4) + 8;
|
||||
}
|
||||
super(0, MSG_ID, size);
|
||||
|
||||
|
||||
if (!buf) {
|
||||
// console.log('Requested Schedule type = ', scheduleType);
|
||||
this.writeInt32LE(0);
|
||||
this.writeInt32LE(scheduleType);
|
||||
} else {
|
||||
this._wroteSize = true;
|
||||
this.writeBuffer(buf, 0);
|
||||
|
||||
this.decode();
|
||||
}
|
||||
}
|
||||
|
||||
decode() {
|
||||
super.decode();
|
||||
|
||||
this.eventCount = this.readUInt32LE();
|
||||
|
||||
this.events = new Array(this.eventCount);
|
||||
|
||||
for (var i = 0; i < this.events.length; i++) {
|
||||
this.events[i] = {};
|
||||
|
||||
this.events[i].scheduleId = this.readUInt32LE();
|
||||
this.events[i].circuitId = this.readUInt32LE();
|
||||
this.events[i].startTime = this.readTime(this.readUInt32LE());
|
||||
this.events[i].stopTime = this.readTime(this.readUInt32LE());
|
||||
this.events[i].dayMask = this.readUInt32LE();
|
||||
this.events[i].flags = this.readUInt32LE();
|
||||
this.events[i].heatCmd = this.readUInt32LE();
|
||||
this.events[i].heatSetPoint = this.readUInt32LE();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
readTime(rawTime) {
|
||||
var retVal;
|
||||
|
||||
retVal = Math.floor(rawTime / 60) * 100 + rawTime % 60;
|
||||
|
||||
retVal = String(retVal).padStart(4, '0');
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
static getResponseId() {
|
||||
return MSG_ID + 1;
|
||||
}
|
||||
};
|
25
messages/SLLightControl.js
Normal file
25
messages/SLLightControl.js
Normal file
@ -0,0 +1,25 @@
|
||||
'use strict';
|
||||
|
||||
const SLMessage = require('./SLMessage.js').SLMessage;
|
||||
|
||||
const MSG_ID = 12556;
|
||||
|
||||
exports.SLLightControl = class SLLightControl extends SLMessage {
|
||||
constructor(controllerIndex, command) {
|
||||
super(0, MSG_ID);
|
||||
|
||||
this.controllerIndex = controllerIndex;
|
||||
this.command = command;
|
||||
}
|
||||
|
||||
encode() {
|
||||
this.writeInt32LE(this.controllerIndex || 0);
|
||||
this.writeInt32LE(this.command || 0);
|
||||
|
||||
super.encode();
|
||||
}
|
||||
|
||||
static getResponseId() {
|
||||
return MSG_ID + 1;
|
||||
}
|
||||
};
|
@ -1,18 +1,28 @@
|
||||
'use strict';
|
||||
|
||||
const SLMessage = require('./SLMessage.js').SLMessage;
|
||||
|
||||
const MSG_ID = 27;
|
||||
|
||||
exports.SLLoginMessage = class SLLoginMessage extends SLMessage {
|
||||
constructor() {
|
||||
constructor(password) {
|
||||
super(0, MSG_ID);
|
||||
this.writeInt32LE(348); // schema
|
||||
this.writeInt32LE(0); // connection type
|
||||
this.writeSLString('node-screenlogic'); // version
|
||||
this.writeSLBuffer(Buffer.alloc(16)); // encoded password. empty/unused for local connections
|
||||
|
||||
if (!password) {
|
||||
password = new Array(16);
|
||||
}
|
||||
if (password.length > 16) {
|
||||
password = password.slice(0, 16);
|
||||
}
|
||||
this.writeSLArray(password); // encoded password. empty/unused for local connections
|
||||
|
||||
this.writeInt32LE(2); // procID
|
||||
}
|
||||
|
||||
static getResponseId() {
|
||||
return MSG_ID + 1;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -1,12 +1,29 @@
|
||||
'use strict';
|
||||
|
||||
const SmartBuffer = require('smart-buffer').SmartBuffer;
|
||||
|
||||
exports.SLMessage = class SLMessage extends SmartBuffer {
|
||||
constructor(senderId, messageId) {
|
||||
super();
|
||||
this.writeUInt16LE(senderId);
|
||||
this.writeUInt16LE(messageId);
|
||||
constructor(senderId, messageId, size) {
|
||||
var options;
|
||||
if (size) {
|
||||
options = {
|
||||
size: size,
|
||||
};
|
||||
}
|
||||
super(options);
|
||||
|
||||
this._wroteSize = false;
|
||||
if (typeof senderId === 'number' || typeof senderId === 'undefined') {
|
||||
this.writeUInt16LE(senderId || 0);
|
||||
this.writeUInt16LE(messageId || 0);
|
||||
|
||||
this._wroteSize = false;
|
||||
} else if (senderId) {
|
||||
this._wroteSize = true;
|
||||
var buffer = senderId;
|
||||
this.writeBuffer(buffer, 0);
|
||||
|
||||
this.decode();
|
||||
}
|
||||
}
|
||||
|
||||
toBuffer() {
|
||||
@ -25,17 +42,13 @@ exports.SLMessage = class SLMessage extends SmartBuffer {
|
||||
writeSLString(str) {
|
||||
this.writeInt32LE(str.length);
|
||||
this.writeString(str);
|
||||
if (str.length % 4 != 0) {
|
||||
this.skipWrite(4 - (str.length % 4));
|
||||
}
|
||||
this.skipWrite(SLMessage.slackForAlignment(str.length));
|
||||
}
|
||||
|
||||
readSLString() {
|
||||
var len = this.readInt32LE();
|
||||
var str = this.readString(len);
|
||||
if (len % 4 != 0) {
|
||||
this.readOffset += 4 - (len % 4);
|
||||
}
|
||||
this.readOffset += SLMessage.slackForAlignment(len);
|
||||
return str;
|
||||
}
|
||||
|
||||
@ -44,6 +57,29 @@ exports.SLMessage = class SLMessage extends SmartBuffer {
|
||||
this.writeBuffer(buf);
|
||||
}
|
||||
|
||||
writeSLArray(arr) {
|
||||
this.writeInt32LE(arr.length);
|
||||
|
||||
for (var i = 0; i < arr.length; i++) {
|
||||
this.writeUInt8(arr[i]);
|
||||
}
|
||||
|
||||
this.skipWrite(SLMessage.slackForAlignment(arr.length));
|
||||
}
|
||||
|
||||
readSLArray() {
|
||||
var len = this.readInt32LE();
|
||||
|
||||
var retval = new Array(len);
|
||||
for (var i = 0; i < len; i++) {
|
||||
retval[i] = this.readUInt8();
|
||||
}
|
||||
|
||||
this.readOffset += SLMessage.slackForAlignment(len);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
skipWrite(num) {
|
||||
if (num > 0) {
|
||||
this.writeBuffer(Buffer.alloc(num));
|
||||
@ -57,7 +93,9 @@ exports.SLMessage = class SLMessage extends SmartBuffer {
|
||||
this.dataLength = this.readInt32LE();
|
||||
}
|
||||
|
||||
encode() {
|
||||
|
||||
static slackForAlignment(val) {
|
||||
return (4 - val % 4) % 4;
|
||||
}
|
||||
}
|
||||
|
||||
encode() {}
|
||||
};
|
||||
|
@ -1,3 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
const SLMessage = require('./SLMessage.js').SLMessage;
|
||||
|
||||
const MSG_ID = 12526;
|
||||
@ -7,7 +9,12 @@ const POOL_CIRCUIT_ID = 505;
|
||||
|
||||
exports.SLPoolStatusMessage = class SLPoolStatusMessage extends SLMessage {
|
||||
constructor(buf) {
|
||||
super(0, MSG_ID);
|
||||
var size;
|
||||
if (buf) {
|
||||
size = buf.readInt32LE(4) + 8;
|
||||
}
|
||||
super(0, MSG_ID, size);
|
||||
|
||||
if (!buf) {
|
||||
this.writeInt32LE(0);
|
||||
} else {
|
||||
@ -60,8 +67,8 @@ exports.SLPoolStatusMessage = class SLPoolStatusMessage extends SLMessage {
|
||||
colorSet: this.readUInt8(),
|
||||
colorPos: this.readUInt8(),
|
||||
colorStagger: this.readUInt8(),
|
||||
delay: this.readUInt8()
|
||||
}
|
||||
delay: this.readUInt8(),
|
||||
};
|
||||
}
|
||||
|
||||
this.pH = this.readInt32LE() / 100;
|
||||
@ -85,23 +92,24 @@ exports.SLPoolStatusMessage = class SLPoolStatusMessage extends SLMessage {
|
||||
return this.ok === 3;
|
||||
}
|
||||
|
||||
isSpaActive() {
|
||||
circuitData(id) {
|
||||
for (let i = 0; i < this.circuitArray.length; i++) {
|
||||
if (this.circuitArray[i].id === SPA_CIRCUIT_ID) {
|
||||
return this.circuitArray[i].state === 1;
|
||||
if (this.circuitArray[i].id === id) {
|
||||
return this.circuitArray[i];
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
isSpaActive() {
|
||||
return this.circuitData(SPA_CIRCUIT_ID).state === 1;
|
||||
}
|
||||
|
||||
isPoolActive() {
|
||||
for (let i = 0; i < this.circuitArray.length; i++) {
|
||||
if (this.circuitArray[i].id === POOL_CIRCUIT_ID) {
|
||||
return this.circuitArray[i].state === 1;
|
||||
}
|
||||
}
|
||||
return this.circuitData(POOL_CIRCUIT_ID).state === 1;
|
||||
}
|
||||
|
||||
static getResponseId() {
|
||||
return MSG_ID + 1;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -1,10 +1,17 @@
|
||||
'use strict';
|
||||
|
||||
const SLMessage = require('./SLMessage.js').SLMessage;
|
||||
|
||||
const MSG_ID = 12572;
|
||||
|
||||
exports.SLSaltCellConfigMessage = class SLSaltCellConfigMessage extends SLMessage {
|
||||
constructor(buf) {
|
||||
super(0, MSG_ID);
|
||||
var size;
|
||||
if (buf) {
|
||||
size = buf.readInt32LE(4) + 8;
|
||||
}
|
||||
super(0, MSG_ID, size);
|
||||
|
||||
if (!buf) {
|
||||
this.writeInt32LE(0); // controller index
|
||||
} else {
|
||||
@ -30,4 +37,4 @@ exports.SLSaltCellConfigMessage = class SLSaltCellConfigMessage extends SLMessag
|
||||
static getResponseId() {
|
||||
return MSG_ID + 1;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
27
messages/SLSetCircuitRuntimeById.js
Normal file
27
messages/SLSetCircuitRuntimeById.js
Normal file
@ -0,0 +1,27 @@
|
||||
'use strict';
|
||||
|
||||
const SLMessage = require('./SLMessage.js').SLMessage;
|
||||
|
||||
const MSG_ID = 12550;
|
||||
|
||||
|
||||
exports.SLSetCircuitRuntimeById = class SLSetCircuitRuntimeById extends SLMessage {
|
||||
constructor(circuitId, runTime) {
|
||||
super(0, MSG_ID);
|
||||
|
||||
this.circuitId = circuitId;
|
||||
this.runTime = runTime;
|
||||
}
|
||||
|
||||
encode() {
|
||||
this.writeInt32LE(0);
|
||||
this.writeInt32LE(this.circuitId);
|
||||
this.writeInt32LE(this.runTime);
|
||||
|
||||
super.encode();
|
||||
}
|
||||
|
||||
static getResponseId() {
|
||||
return MSG_ID + 1;
|
||||
}
|
||||
};
|
@ -1,14 +1,16 @@
|
||||
'use strict';
|
||||
|
||||
const SLMessage = require('./SLMessage.js').SLMessage;
|
||||
|
||||
const MSG_ID = 12530;
|
||||
|
||||
exports.SLSetCircuitStateMessage = class SLSetCircuitStateMessage extends SLMessage {
|
||||
constructor(controllerId, circuitId, circuitState) {
|
||||
super(0, MSG_ID);
|
||||
super(0, MSG_ID);
|
||||
|
||||
this.controllerId = controllerId;
|
||||
this.circuitId = circuitId;
|
||||
this.circuitState = circuitState;
|
||||
this.controllerId = controllerId;
|
||||
this.circuitId = circuitId;
|
||||
this.circuitState = circuitState;
|
||||
}
|
||||
|
||||
encode() {
|
||||
@ -22,4 +24,4 @@ exports.SLSetCircuitStateMessage = class SLSetCircuitStateMessage extends SLMess
|
||||
static getResponseId() {
|
||||
return MSG_ID + 1;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
29
messages/SLSetHeatMode.js
Normal file
29
messages/SLSetHeatMode.js
Normal file
@ -0,0 +1,29 @@
|
||||
'use strict';
|
||||
|
||||
const SLMessage = require('./SLMessage.js').SLMessage;
|
||||
|
||||
const MSG_ID = 12538;
|
||||
|
||||
exports.SLSetHeatMode = class SLSetHeatMode extends SLMessage {
|
||||
constructor(controllerIndex, bodyType, heatMode) {
|
||||
super(0, MSG_ID);
|
||||
|
||||
this.controllerIndex = controllerIndex;
|
||||
this.bodyType = bodyType;
|
||||
this.heatMode = heatMode;
|
||||
// heatmodes:
|
||||
// 0: "Off", 1: "Solar", 2 : "Solar Preferred", 3 : "Heat Pump", 4: "Don't Change"
|
||||
}
|
||||
|
||||
encode() {
|
||||
this.writeInt32LE(this.controllerIndex || 0);
|
||||
this.writeInt32LE(this.bodyType || 0);
|
||||
this.writeInt32LE(this.heatMode || 0);
|
||||
|
||||
super.encode();
|
||||
}
|
||||
|
||||
static getResponseId() {
|
||||
return MSG_ID + 1;
|
||||
}
|
||||
};
|
27
messages/SLSetHeatSetPoint.js
Normal file
27
messages/SLSetHeatSetPoint.js
Normal file
@ -0,0 +1,27 @@
|
||||
'use strict';
|
||||
|
||||
const SLMessage = require('./SLMessage.js').SLMessage;
|
||||
|
||||
const MSG_ID = 12528;
|
||||
|
||||
exports.SLSetHeatSetPoint = class SLSetHeatSetPoint extends SLMessage {
|
||||
constructor(controllerIndex, bodyType, temperature) {
|
||||
super(0, MSG_ID);
|
||||
|
||||
this.controllerIndex = controllerIndex;
|
||||
this.bodyType = bodyType;
|
||||
this.temperature = temperature;
|
||||
}
|
||||
|
||||
encode() {
|
||||
this.writeInt32LE(this.controllerIndex || 0);
|
||||
this.writeInt32LE(this.bodyType || 0);
|
||||
this.writeInt32LE(this.temperature || 0);
|
||||
|
||||
super.encode();
|
||||
}
|
||||
|
||||
static getResponseId() {
|
||||
return MSG_ID + 1;
|
||||
}
|
||||
};
|
29
messages/SLSetSaltCellConfigMessage.js
Normal file
29
messages/SLSetSaltCellConfigMessage.js
Normal file
@ -0,0 +1,29 @@
|
||||
'use strict';
|
||||
|
||||
const SLMessage = require('./SLMessage.js').SLMessage;
|
||||
|
||||
const MSG_ID = 12576;
|
||||
|
||||
exports.SLSetSaltCellConfigMessage = class SLSetSaltCellConfigMessage extends SLMessage {
|
||||
constructor(controllerIndex, poolOutput, spaOutput) {
|
||||
super(0, MSG_ID);
|
||||
|
||||
this.controllerIndex = controllerIndex;
|
||||
this.poolOutput = poolOutput;
|
||||
this.spaOutput = spaOutput;
|
||||
}
|
||||
|
||||
encode() {
|
||||
this.writeInt32LE(this.controllerIndex || 0);
|
||||
this.writeInt32LE(this.poolOutput || 0);
|
||||
this.writeInt32LE(this.spaOutput || 0);
|
||||
this.writeInt32LE(0);
|
||||
this.writeInt32LE(0);
|
||||
|
||||
super.encode();
|
||||
}
|
||||
|
||||
static getResponseId() {
|
||||
return MSG_ID + 1;
|
||||
}
|
||||
};
|
38
messages/SLSetScheduleEventById.js
Normal file
38
messages/SLSetScheduleEventById.js
Normal file
@ -0,0 +1,38 @@
|
||||
'use strict';
|
||||
|
||||
const SLMessage = require('./SLMessage.js').SLMessage;
|
||||
|
||||
const MSG_ID = 12548;
|
||||
|
||||
|
||||
exports.SLSetScheduleEventById = class SLSetScheduleEventById extends SLMessage {
|
||||
constructor(buf, scheduleId, circuitId, startTime, stopTime, dayMask, flags, heatCmd, heatSetPoint) {
|
||||
var size;
|
||||
if (buf) {
|
||||
size = buf.readInt32LE(4) + 8;
|
||||
}
|
||||
super(0, MSG_ID, size);
|
||||
|
||||
|
||||
if (!buf) {
|
||||
this.writeInt32LE(0);
|
||||
this.writeInt32LE(scheduleId);
|
||||
this.writeInt32LE(circuitId);
|
||||
this.writeInt32LE(startTime);
|
||||
this.writeInt32LE(stopTime);
|
||||
this.writeInt32LE(dayMask);
|
||||
this.writeInt32LE(flags);
|
||||
this.writeInt32LE(heatCmd);
|
||||
this.writeInt32LE(heatSetPoint);
|
||||
} else {
|
||||
this._wroteSize = true;
|
||||
this.writeBuffer(buf, 0);
|
||||
|
||||
this.decode();
|
||||
}
|
||||
}
|
||||
|
||||
static getResponseId() {
|
||||
return MSG_ID + 1;
|
||||
}
|
||||
};
|
@ -1,10 +1,17 @@
|
||||
'use strict';
|
||||
|
||||
const SLMessage = require('./SLMessage.js').SLMessage;
|
||||
|
||||
const MSG_ID = 8120;
|
||||
|
||||
exports.SLVersionMessage = class SLVersionMessage extends SLMessage {
|
||||
constructor(buf) {
|
||||
super(0, MSG_ID);
|
||||
var size;
|
||||
if (buf) {
|
||||
size = buf.readInt32LE(4) + 8;
|
||||
}
|
||||
super(0, MSG_ID, size);
|
||||
|
||||
if (buf) {
|
||||
this._wroteSize = true;
|
||||
this.writeBuffer(buf, 0);
|
||||
@ -22,4 +29,4 @@ exports.SLVersionMessage = class SLVersionMessage extends SLMessage {
|
||||
static getResponseId() {
|
||||
return MSG_ID + 1;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -1,8 +1,22 @@
|
||||
exports.SLPoolStatusMessage = require("./SLPoolStatusMessage.js").SLPoolStatusMessage;
|
||||
exports.SLControllerConfigMessage = require("./SLControllerConfigMessage.js").SLControllerConfigMessage;
|
||||
exports.SLChallengeMessage = require("./SLChallengeMessage.js").SLChallengeMessage;
|
||||
exports.SLLoginMessage = require("./SLLoginMessage.js").SLLoginMessage;
|
||||
exports.SLChemDataMessage = require("./SLChemDataMessage.js").SLChemDataMessage;
|
||||
exports.SLSaltCellConfigMessage = require("./SLSaltCellConfigMessage.js").SLSaltCellConfigMessage;
|
||||
exports.SLVersionMessage = require("./SLVersionMessage.js").SLVersionMessage;
|
||||
exports.SLSetCircuitStateMessage = require("./SLSetCircuitStateMessage.js").SLSetCircuitStateMessage;
|
||||
'use strict';
|
||||
|
||||
exports.SLPoolStatusMessage = require('./SLPoolStatusMessage.js').SLPoolStatusMessage;
|
||||
exports.SLControllerConfigMessage = require('./SLControllerConfigMessage.js').SLControllerConfigMessage;
|
||||
exports.SLChallengeMessage = require('./SLChallengeMessage.js').SLChallengeMessage;
|
||||
exports.SLLoginMessage = require('./SLLoginMessage.js').SLLoginMessage;
|
||||
exports.SLChemDataMessage = require('./SLChemDataMessage.js').SLChemDataMessage;
|
||||
exports.SLSaltCellConfigMessage = require('./SLSaltCellConfigMessage.js').SLSaltCellConfigMessage;
|
||||
exports.SLVersionMessage = require('./SLVersionMessage.js').SLVersionMessage;
|
||||
exports.SLSetCircuitStateMessage = require('./SLSetCircuitStateMessage.js').SLSetCircuitStateMessage;
|
||||
exports.SLGetGatewayDataMessage = require('./SLGetGatewayDataMessage.js').SLGetGatewayDataMessage;
|
||||
exports.SLSetHeatSetPointMessage = require('./SLSetHeatSetPoint.js').SLSetHeatSetPoint;
|
||||
exports.SLSetHeatModeMessage = require('./SLSetHeatMode.js').SLSetHeatMode;
|
||||
exports.SLLightControlMessage = require('./SLLightControl.js').SLLightControl;
|
||||
exports.SLSetSaltCellConfigMessage = require('./SLSetSaltCellConfigMessage.js').SLSetSaltCellConfigMessage;
|
||||
exports.SLEquipmentConfigurationMessage =
|
||||
require('./SLEquipmentConfigurationMessage.js').SLEquipmentConfigurationMessage;
|
||||
exports.SLGetScheduleData = require('./SLGetScheduleData.js').SLGetScheduleData;
|
||||
exports.SLAddNewScheduleEvent = require('./SLAddNewScheduleEvent.js').SLAddNewScheduleEvent;
|
||||
exports.SLDeleteScheduleEventById = require('./SLDeleteScheduleEventById.js').SLDeleteScheduleEventById;
|
||||
exports.SLSetScheduleEventById = require('./SLSetScheduleEventById.js').SLSetScheduleEventById;
|
||||
exports.SLSetCircuitRuntimeById = require('./SLSetCircuitRuntimeById.js').SLSetCircuitRuntimeById;
|
||||
|
1863
package-lock.json
generated
Normal file
1863
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
14
package.json
14
package.json
@ -1,11 +1,10 @@
|
||||
{
|
||||
"name": "node-screenlogic",
|
||||
"description": "Tool for connecting to Pentair ScreenLogic systems on the local network",
|
||||
"version": "1.1.0",
|
||||
"version": "1.5.0",
|
||||
"main": "index.js",
|
||||
"license": "MIT",
|
||||
"repository": "https://github.com/parnic/node-screenlogic.git",
|
||||
"main": "index.js",
|
||||
"keywords": [
|
||||
"pentair",
|
||||
"pool",
|
||||
@ -13,6 +12,15 @@
|
||||
"swimmingpool"
|
||||
],
|
||||
"dependencies": {
|
||||
"smart-buffer": "~4.0.1"
|
||||
"smart-buffer": "~4.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint": "^7.2.0",
|
||||
"eslint-config-strongloop": "^2.1.0",
|
||||
"mocha": "^7.2.0"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "mocha test/*.spec.js",
|
||||
"pretest": "eslint --ignore-path .gitignore ."
|
||||
}
|
||||
}
|
||||
|
15
test/find.spec.js
Normal file
15
test/find.spec.js
Normal file
@ -0,0 +1,15 @@
|
||||
'use strict';
|
||||
|
||||
const ScreenLogic = require('../index');
|
||||
|
||||
// you'll need a ScreenLogic-enabled device on your network for this to succeed
|
||||
describe('Finder', () => {
|
||||
it('finds a server', done => {
|
||||
let finder = new ScreenLogic.FindUnits();
|
||||
finder.on('serverFound', server => {
|
||||
finder.close();
|
||||
done();
|
||||
});
|
||||
finder.search();
|
||||
});
|
||||
});
|
175
test/slmessage.spec.js
Normal file
175
test/slmessage.spec.js
Normal file
@ -0,0 +1,175 @@
|
||||
'use strict';
|
||||
|
||||
const SLMessage = require('../messages/SLMessage.js').SLMessage;
|
||||
const assert = require('assert');
|
||||
|
||||
function slMessageLen(str) {
|
||||
// strings have length prefixed on them as an int32 for an additional 4b.
|
||||
// strings are dword aligned, so if str.length is 21, dword alignment pushes it up to 24
|
||||
return 4 + str.length + SLMessage.slackForAlignment(str.length);
|
||||
}
|
||||
|
||||
describe('SLMessage utilities', () => {
|
||||
// message header = senderId, messageId, bodyLen.
|
||||
// senderId and messageId are int16's, so 2b each. bodyLen is an int32, so 4b. total 8b.
|
||||
let msgHeaderLen = 8;
|
||||
|
||||
it('sets senderId and messageId properly', function() {
|
||||
{
|
||||
let msg = new SLMessage(123, 456);
|
||||
let decodedMsg = new SLMessage(msg.toBuffer());
|
||||
assert.strictEqual(decodedMsg.senderId, 123);
|
||||
assert.strictEqual(decodedMsg.messageId, 456);
|
||||
assert.strictEqual(decodedMsg.dataLength, 0);
|
||||
}
|
||||
|
||||
{
|
||||
let msg = new SLMessage(0, 65534);
|
||||
let decodedMsg = new SLMessage(msg.toBuffer());
|
||||
assert.strictEqual(decodedMsg.senderId, 0);
|
||||
assert.strictEqual(decodedMsg.messageId, 65534);
|
||||
assert.strictEqual(decodedMsg.dataLength, 0);
|
||||
}
|
||||
|
||||
{
|
||||
let msg = new SLMessage();
|
||||
let decodedMsg = new SLMessage(msg.toBuffer());
|
||||
assert.strictEqual(decodedMsg.senderId, 0);
|
||||
assert.strictEqual(decodedMsg.messageId, 0);
|
||||
assert.strictEqual(decodedMsg.dataLength, 0);
|
||||
}
|
||||
|
||||
{
|
||||
let msg = new SLMessage(123);
|
||||
let decodedMsg = new SLMessage(msg.toBuffer());
|
||||
assert.strictEqual(decodedMsg.senderId, 123);
|
||||
assert.strictEqual(decodedMsg.messageId, 0);
|
||||
assert.strictEqual(decodedMsg.dataLength, 0);
|
||||
}
|
||||
|
||||
{
|
||||
let msg = new SLMessage(0);
|
||||
let decodedMsg = new SLMessage(msg.toBuffer());
|
||||
assert.strictEqual(decodedMsg.senderId, 0);
|
||||
assert.strictEqual(decodedMsg.messageId, 0);
|
||||
assert.strictEqual(decodedMsg.dataLength, 0);
|
||||
}
|
||||
});
|
||||
|
||||
it('encodes and decodes SLStrings', function() {
|
||||
{
|
||||
let msg = new SLMessage();
|
||||
let testStr = 'this is a test string';
|
||||
msg.writeSLString(testStr);
|
||||
let decodedMsg = new SLMessage(msg.toBuffer());
|
||||
assert.strictEqual(decodedMsg.readSLString(), testStr, 'did not receive serialized message properly');
|
||||
assert.strictEqual(SLMessage.slackForAlignment(testStr.length), 3);
|
||||
// SLString byte length = 4 + 21 + 3 = 28b
|
||||
assert.strictEqual(slMessageLen(testStr),
|
||||
4 + testStr.length + SLMessage.slackForAlignment(testStr.length));
|
||||
assert.strictEqual(decodedMsg.readOffset, msgHeaderLen + slMessageLen(testStr), 'read offset was invalid');
|
||||
assert.strictEqual(decodedMsg.dataLength, decodedMsg.readOffset - 8);
|
||||
}
|
||||
|
||||
{
|
||||
let msg = new SLMessage();
|
||||
let testStr = '1';
|
||||
msg.writeSLString(testStr);
|
||||
let decodedMsg = new SLMessage(msg.toBuffer());
|
||||
assert.strictEqual(decodedMsg.readSLString(), testStr, 'did not receive serialized message properly');
|
||||
assert.strictEqual(SLMessage.slackForAlignment(testStr.length), 3);
|
||||
assert.strictEqual(decodedMsg.readOffset, msgHeaderLen + slMessageLen(testStr), 'read offset was invalid');
|
||||
assert.strictEqual(decodedMsg.dataLength, decodedMsg.readOffset - 8);
|
||||
}
|
||||
|
||||
{
|
||||
let msg = new SLMessage();
|
||||
let testStr = '12';
|
||||
msg.writeSLString(testStr);
|
||||
let decodedMsg = new SLMessage(msg.toBuffer());
|
||||
assert.strictEqual(decodedMsg.readSLString(), testStr, 'did not receive serialized message properly');
|
||||
assert.strictEqual(SLMessage.slackForAlignment(testStr.length), 2);
|
||||
assert.strictEqual(decodedMsg.readOffset, msgHeaderLen + slMessageLen(testStr), 'read offset was invalid');
|
||||
assert.strictEqual(decodedMsg.dataLength, decodedMsg.readOffset - 8);
|
||||
}
|
||||
|
||||
{
|
||||
let msg = new SLMessage();
|
||||
let testStr = '123';
|
||||
msg.writeSLString(testStr);
|
||||
let decodedMsg = new SLMessage(msg.toBuffer());
|
||||
assert.strictEqual(decodedMsg.readSLString(), testStr, 'did not receive serialized message properly');
|
||||
assert.strictEqual(SLMessage.slackForAlignment(testStr.length), 1);
|
||||
assert.strictEqual(decodedMsg.readOffset, msgHeaderLen + slMessageLen(testStr), 'read offset was invalid');
|
||||
assert.strictEqual(decodedMsg.dataLength, decodedMsg.readOffset - 8);
|
||||
}
|
||||
|
||||
{
|
||||
let msg = new SLMessage();
|
||||
let testStr = '1234';
|
||||
msg.writeSLString(testStr);
|
||||
let decodedMsg = new SLMessage(msg.toBuffer());
|
||||
assert.strictEqual(decodedMsg.readSLString(), testStr, 'did not receive serialized message properly');
|
||||
assert.strictEqual(SLMessage.slackForAlignment(testStr.length), 0);
|
||||
assert.strictEqual(decodedMsg.readOffset, msgHeaderLen + slMessageLen(testStr), 'read offset was invalid');
|
||||
assert.strictEqual(decodedMsg.dataLength, decodedMsg.readOffset - 8);
|
||||
}
|
||||
});
|
||||
|
||||
it('encodes and decodes SLArrays', function() {
|
||||
{
|
||||
let msg = new SLMessage();
|
||||
let list = [];
|
||||
msg.writeSLArray(list);
|
||||
let decodedMsg = new SLMessage(msg.toBuffer());
|
||||
assert.deepStrictEqual(decodedMsg.readSLArray(), list);
|
||||
assert.strictEqual(SLMessage.slackForAlignment(list.length), 0);
|
||||
assert.strictEqual(decodedMsg.readOffset, msgHeaderLen + slMessageLen(list), 'read offset was invalid');
|
||||
assert.strictEqual(decodedMsg.dataLength, decodedMsg.readOffset - 8);
|
||||
}
|
||||
|
||||
{
|
||||
let msg = new SLMessage();
|
||||
let list = [1];
|
||||
msg.writeSLArray(list);
|
||||
let decodedMsg = new SLMessage(msg.toBuffer());
|
||||
assert.deepStrictEqual(decodedMsg.readSLArray(), list);
|
||||
assert.strictEqual(SLMessage.slackForAlignment(list.length), 3);
|
||||
assert.strictEqual(decodedMsg.readOffset, msgHeaderLen + slMessageLen(list), 'read offset was invalid');
|
||||
assert.strictEqual(decodedMsg.dataLength, decodedMsg.readOffset - 8);
|
||||
}
|
||||
|
||||
{
|
||||
let msg = new SLMessage();
|
||||
let list = [1, 2];
|
||||
msg.writeSLArray(list);
|
||||
let decodedMsg = new SLMessage(msg.toBuffer());
|
||||
assert.deepStrictEqual(decodedMsg.readSLArray(), list);
|
||||
assert.strictEqual(SLMessage.slackForAlignment(list.length), 2);
|
||||
assert.strictEqual(decodedMsg.readOffset, msgHeaderLen + slMessageLen(list), 'read offset was invalid');
|
||||
assert.strictEqual(decodedMsg.dataLength, decodedMsg.readOffset - 8);
|
||||
}
|
||||
|
||||
{
|
||||
let msg = new SLMessage();
|
||||
let list = [1, 2, 3];
|
||||
msg.writeSLArray(list);
|
||||
let decodedMsg = new SLMessage(msg.toBuffer());
|
||||
assert.deepStrictEqual(decodedMsg.readSLArray(), list);
|
||||
assert.strictEqual(SLMessage.slackForAlignment(list.length), 1);
|
||||
assert.strictEqual(decodedMsg.readOffset, msgHeaderLen + slMessageLen(list), 'read offset was invalid');
|
||||
assert.strictEqual(decodedMsg.dataLength, decodedMsg.readOffset - 8);
|
||||
}
|
||||
|
||||
{
|
||||
let msg = new SLMessage();
|
||||
let list = [1, 2, 3, 4];
|
||||
msg.writeSLArray(list);
|
||||
let decodedMsg = new SLMessage(msg.toBuffer());
|
||||
assert.deepStrictEqual(decodedMsg.readSLArray(), list);
|
||||
assert.strictEqual(SLMessage.slackForAlignment(list.length), 0);
|
||||
assert.strictEqual(decodedMsg.readOffset, msgHeaderLen + slMessageLen(list), 'read offset was invalid');
|
||||
assert.strictEqual(decodedMsg.dataLength, decodedMsg.readOffset - 8);
|
||||
}
|
||||
});
|
||||
});
|
74
test/unit.spec.js
Normal file
74
test/unit.spec.js
Normal file
@ -0,0 +1,74 @@
|
||||
'use strict';
|
||||
|
||||
const ScreenLogic = require('../index');
|
||||
|
||||
// you'll need a ScreenLogic-enabled device on your network for this to succeed
|
||||
describe('Unit', () => {
|
||||
let unit;
|
||||
before(done => {
|
||||
let finder = new ScreenLogic.FindUnits();
|
||||
finder.on('serverFound', server => {
|
||||
finder.close();
|
||||
|
||||
unit = new ScreenLogic.UnitConnection(server);
|
||||
unit.on('loggedIn', () => {
|
||||
done();
|
||||
});
|
||||
|
||||
unit.connect();
|
||||
});
|
||||
|
||||
finder.search();
|
||||
});
|
||||
|
||||
after(() => {
|
||||
unit.close();
|
||||
});
|
||||
|
||||
// let circuit;
|
||||
it('gets pool status', done => {
|
||||
unit.on('poolStatus', status => {
|
||||
/* circuit = */status.circuitArray[0];
|
||||
done();
|
||||
});
|
||||
|
||||
unit.getPoolStatus();
|
||||
});
|
||||
|
||||
it('gets controller config', done => {
|
||||
unit.on('controllerConfig', config => {
|
||||
done();
|
||||
});
|
||||
unit.getControllerConfig();
|
||||
});
|
||||
|
||||
it('gets chemical data', done => {
|
||||
unit.on('chemicalData', () => {
|
||||
done();
|
||||
});
|
||||
unit.getChemicalData();
|
||||
});
|
||||
|
||||
it('gets salt cell config', done => {
|
||||
unit.on('saltCellConfig', () => {
|
||||
done();
|
||||
});
|
||||
unit.getSaltCellConfig();
|
||||
});
|
||||
|
||||
it('gets version', done => {
|
||||
unit.on('version', () => {
|
||||
done();
|
||||
});
|
||||
unit.getVersion();
|
||||
});
|
||||
|
||||
/* uncomment this and the `circuit` stuff above to test setting state
|
||||
it('sets circuit state', done => {
|
||||
unit.on('circuitStateChanged', () => {
|
||||
done();
|
||||
});
|
||||
unit.setCircuitState(0, circuit.id, circuit.state);
|
||||
});
|
||||
*/
|
||||
});
|
Reference in New Issue
Block a user