Code Monkey home page Code Monkey logo

node-screenlogic's Issues

History messages

Anybody got any luck/experience with history messsages?

From what I figured out looking at the android apps comms:
Sending a 12534 type requests history events.
Format is:
Int32(0), DateTime(start), DateTime(end)
with DateTime encoded as:
Uint16(year), Uint16(month), Uint16(Day of week, can be ignored/0), Uint16(day), Uint16(hour), Uint16(minute), Uint32?(seconds)

It'll come back with an empty 12535.

It then send a (very long) message 12502 with the format:

Uint32(Number of events)
for (event in number events):
DateTime(event timestamp)
Uint32(Outside Temperature)

So basically so far I've been able to get the outside temperature read out, but I have no clue how to figure out when the pump/heater/light was on. Anyone any idea?

Unit is found but remote connection is hanging?

Hi!

Having a weird issue -- the unit is found, but the network connection fails.

const ScreenLogic = require("node-screenlogic");

const username = ".......";
const password = ".......";

const rl = new ScreenLogic.RemoteLogin(username);

rl.on('gatewayFound', function(unit) {
    console.log('Found unit');
    console.log(JSON.stringify(unit));
    const unitConnection = new ScreenLogic.UnitConnection(unit.port, unit.ipAddr, password);
    console.log('trying to connect');
    try {
        unitConnection.on('connected', function() {
            console.log('connected');
            unitConnection.getPoolStatus((status) => {
                console.log(status);
            });
        });
        unitConnection.on('error', function(error) {
            console.log(error);
        });
        unitConnection.connect();
    
    } catch (error) {
        console.log(error);
    }
});

rl.connect();

The Unit data is sent back properly, the port is open.
The connection to the unit itself fails after a few moments:

Error: read ECONNRESET at TCP.onStreamRead (node:internal/stream_base_commons:217:20) { errno: -54, code: 'ECONNRESET', syscall: 'read' }

Any ideas how to debug this?

Get Circuit State (on, off, etc.)

We are trying to get the circuit state of something like the waterfalls so we know if they are on or off. We read all the documentation and couldn't figure out how to do this. Did we miss something or is this impossible?

We tried getCircuitByDeviceId(), but it said the function is not defined.
We also tried looking at ...}).on('controllerConfig', function (config) { config.bodyArray[<index of circuit>]..., but it didn't give us the information we need.

Testing Needed for SLGetPumpStatus / SLSetPumpFlow

@mikemucc and @parnic

I implemented the above messages, but need feedback from someone with more than one VS pump as I have no way to know for sure how to set/request data for other pumps, i made an educated guess based on the other messages.

you can checkout my branch:
https://github.com/bshep/node-screenlogic/tree/pump_info

you can use this example file to test:
https://gist.github.com/bshep/0f900eabe699d141bd4a33d60907037f

edit the line 51:

this.getPumpStatus(0);

to request other pumps ( it may not work if i guessed wrong )

Please also test ( this WILL change your settings so make sure you have some way of setting them back if something fails):

setPumpFlow(pumpId, circuitId, setPoint, isRPMs)

I've tested with 'pumpId = 0' and it works perfectly

Once more testing has been done I will submit a PR to have it merged.

any ideas on how to set setPoint (for spa heater)?

I assume I need the equivalent of setCircuitState. Here's the function I'm using to turn the spa on (circuit ID 500) and then call getPoolState() to publish status to my network.

Thoughts?

    function connect(client) {
      client.on('loggedIn', function() {
        this.setCircuitState(0, 500, 1);
        console.log('Spa turned on')
        client.close();
        wait(500).then( getPoolState())
        .then(console.log('called getPoolState'))
      });
  
      client.connect();

Socket reads only first chunk (1024 bytes).

Hello.
When I am runing this.getPoolStatus(); I get error: Attempted to read beyond the bounds of the managed data.

Error: Attempted to read beyond the bounds of the managed data.
smartbuffer.js:957
at SLControllerConfigMessage.ensureReadable (d:\node-screenlogic-master\node_modules\smart-buffer\build\smartbuffer.js:957:19)
at SLControllerConfigMessage._readNumberValue (d:\node-screenlogic-master\node_modules\smart-buffer\build\smartbuffer.js:1025:14)
at SLControllerConfigMessage.readInt32LE (d:\node-screenlogic-master\node_modules\smart-buffer\build\smartbuffer.js:145:21)
at SLControllerConfigMessage.decode (d:\node-screenlogic-master\messages\SLControllerConfigMessage.js:65:19)
at new SLControllerConfigMessage (d:\node-screenlogic-master\messages\SLControllerConfigMessage.js:17:12)
at UnitConnection.onClientMessage (d:\node-screenlogic-master\index.js:219:39)
at Socket. (d:\node-screenlogic-master\index.js:131:15)
at Socket.emit (events.js:182:13)
at addChunk (_stream_readable.js:283:12)
at readableAddChunk (_stream_readable.js:264:11)

I investigated this problem. Data send in two chunks, but app don't wait second chunk.

My fix for UnitConnection class:

var buffer = Buffer.from("", 'binary');
this.client.on('data', function(msg) {
buffer = Buffer.concat([buffer, msg]);
if (msg.length!=1024) {
_this.onClientMessage(buffer);
buffer = Buffer.from("", 'binary');
}
}).on('close', function(had_error) {
// console.log('unit connection closed');
});

received message of length 1196

addClient disconnecting

Thanks for this library, it's great! I'm using the addClient() function to subscribe to updates from the controller which works fine, but it seems to disconnect after about 20 minutes or so and stop receiving updates. Also if I try to send commands to the controller after that, it gives me an error that says "this socket has been ended by the other party". Can anyone else confirm this? Is there some autoreconnect procedure? I want to have a persistent 24/7 connection to the controller.

Unable to set salt level for pool or spa individually

The setSaltCellOutput function sets the pool and spa levels so you can't just send one level. Would it be possible to either create distinct functions for pool and spa or add the ability to pass null values to the existing function like this:

exports.SLSetSaltCellConfigMessage = class SLSetSaltCellConfigMessage extends SLMessage {
  constructor(controllerIndex, poolOutput, spaOutput) {
    super(0, MSG_ID);
    this.controllerIndex = controllerIndex;
    if(poolOutput != null){
      this.poolOutput = poolOutput;
    }
    if(spaOutput != null){
      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;
  }
};

I'm not sure how the messages are sent to SL so this might not be possible, but it would make sense to allow just setting one at a time.

Can you tell if a scheduled event is running or not?

Thanks so much for this project. Super useful.

In the ScreenLogic app when you look at the scheduled events (at least on the iOS version), it highlights jobs in green when they are running. Any idea if this running state is queried from the controller or is the app just being smart and looking at the current time and the state of the circuit and assuming the schedule is the reason for it being active? The reason I ask is I notice the onboard clock can get off over time and the time window drift because of it so assuming both controller and my code are on the same time isn't a great assumption. I'm assuming that the controller has a way to query this info for the app but I'm not seeing it in the code/doc.

Related question, is there a way to get the current time on the controller to determine if it is reasonably in synch?

Thanks!!

How to cancel the default pool delays?

Love the API! Is there an API I can use to cancel the default pool delays? My controller automatically runs the pool and spa for 2 mins on my system after turning off the spa.

Set Control for the Salt Cell Output

First I want to say I love this Library! totally awesome.

Per our previous postings...

I would like to make a feature request for Set Control for the Salt Cell Output.

User Story: I have both an IntelliChem and an IntelliChlor. I have noticed that the IntelliChem control for my SaltCell isn't very intelligent. It's set up so that if the SaltCell can't keep up with the Chlorine output then it adds Chlorine from the tank. The issue is that it doesn't just attempt to increase the Setting on the Salt Cell first. The problem is that I don't find out that the salt cell is set too low until I get an error that my ORP Tank is empty... I am feeding ORP Stats into an AI now using your library (Awesome)! and I would like that system to be able to control my SaltCell based on the results.

Thanks so much for hearing me out and I am happy to know that it's not just me having this issue.

Heat Status Code 1 Meaning?

I'm actually trying to wrap your code into a polling REST API using express.js.

Right now I'm just working on getting the status of the pool and I'm working through the heater status options.

I was able to figure out what the heater mode codes are from that PDF published by Carson Eisenach, but I'm not sure what the heat status codes are.

From my own observations I've been able to glean the following:
0 = off
2 = on (gas heater)

Would you perchance know what does a heat status code 1 mean?

If I were going to guess, I'd guess it means "Solar On", since the lower non-zero codes for heat mode refer to Solar, but I figured I'd ask the expert.

Calling getPumpStatus() is timing out.

Hi Parnic, I have created a REST webservice using your Library and I love it!

Recently, I have been asked to expand to capture more Pump info and I noticed you added Pump Functions to the library.

I created a copy of example.js and added the get getPumpStatus(). It seems to be timing out on that one function.

Any ideas?

}).on('saltCellConfig', function(saltCellConfig) { this.getControllerConfig(); console.log(' salt cell installed=' + saltCellConfig.installed); //Adding Pump }).on('pumpStatus', function(pumpStatus) { this.getPumpStatus(0); console.log(' Pump Status =' + pumpStatus.isRunning); //Pump End }).on('controllerConfig', function(config) { console.log(' controller is in celsius=' + config.degC); client.close();

getNumPumps() returns number of available pump slots, not actual number of pumps

As always, thanks for this work!

On my system I have one filter pump configured in the controller and it has pump circulation settings for the pool and spa set for it. If you call getNumPumps() you (at least I) get 8 back always as the result. Looking at the data coming back from the controller and adding a phantom 2nd pump to see how the data changed, I believe I see where the issue is. Currently the code in getNumPumps() loops through the 45 byte record for each pump record and checks the 3rd byte in the array to see if it's non-zero. For me this value is always 2 no matter what I do so every record in the list (all 8) are seen as a pump and the counter incremented.

Looking at the data, particularly the first 3 bytes of each 45 byte record, I get the following for the first record (where my IntelliFlo VSF pump is):

0x40, 0x0,0x2

For all the remaining records where I have no pump, each one starts with:

0x0,0xF,0x2

When I created my phantom pump, only byte 0 changed, depending on what pump type I chose in SLConfig. Byte 1 and 2 didn't change from 0xF and 0x2. Not sure what byte 1 represents but given it's 0 for my real pump and 0xF for the phantom one, it's probably some sort of status about the pump that the controller can't get from my fake pump.

Byte 0 took the following values:
0 = None selected in SLConfig for pump type
0x6 = IntelliFlo VF
0x40 = IntelliFlo VSF
0x80 = IntelliFlo VS

So I think the code in getNumPumps should be looking at byte 0 rather than byte 2 for whether there's a pump there (unless it is really intended to return the number of potential slots vs. actual pumps). The values for the various pump models shown above don't seem to match the values returned by the GetPumpStatus msg but my VSF reports 3 so I think that mapping is accurate otherwise. The values above for pump type track repeatedly to what is set in SLConfig.

Can anyone confirm that they get 8 pumps from getNumPumps()? I don't see a way to get rid of the unused pump slots so I assume that the controller just always has 8 slots no matter how many pumps you may actually have and you have to see if a pump is actually set for that slot before counting it.

Homebridge Compatibility

Hello parnic!

Not really an issue but was wondering if you were looking into creating a homebridge version of this so that Pumps can be controlled through Apple's HomeKit?

Thanks for your awesome work so far!

Schedule Editing

I'm really interested in being able to configure the schedule remotely, i wonder if i can help by providing some packet captures?

I have PC app and wireshark available but i'm not sure what to look for.

Basic question from a novice: Truncated example.js output

when I first used this example function months ago I saw the full result to console. Now when I run the example I see only the result of the first get equipment config only. What am I missing? I dont see in example anything that would prevent the subsequent functions to display their data to console.

C:\Users\Chris\Desktop\node_screenlogic\node_modules\node-screenlogic>node example
version = 1180
secondaries = 0
pump 1 type=0, pump 2 type=2
pump 1 pool rpm=2000
pump 2 waterfall rpm=0
num pumps=7

C:\Users\Chris\Desktop\node_screenlogic\node_modules\node-screenlogic>

Uncaught Exception crashing node-red

This is the only information I can find in the logs:

9 May 07:31:47 - [red] Uncaught Exception:
9 May 07:31:47 - Error: read ECONNRESET at TCP.onStreamRead (internal/stream_base_commons.js:209:20)

This occurs 30 seconds after node-red starts. I have node-red auto starting on failure. So, this puts it into a cycle of start/die in 30 seconds/restart/die in 30 seconds... for ever.

Below is the node-red function on start code. Other than the fatal crash, everything appears to be working normally:


node.status({fill:'yellow',shape:'dot',text:'Loading'});

const systemName = 'Pentair: xx-xx-xx;
const password = '';

var screenLogic = global.get('screenlogic');
var remote = new screenLogic.RemoteLogin(systemName);

var pool = {};

remote.on('gatewayFound', function(unit) {
  if (unit && unit.gatewayFound) {
    var client = new screenLogic.UnitConnection(unit.port, unit.ipAddr, password);
    client.on('loggedIn', function() {
        pool.systemName = remote.systemName;
        pool.ip = unit.ipAddr;
        pool.port = unit.port;
        node.status({fill:'green',shape:'dot',text:'connected, getting version'});
        this.getVersion();
    }).on('version', function(version) {
        pool.version = version.version;
        node.status({fill:'green',shape:'dot',text:'connected, getting status'});
        this.getPoolStatus();
    }).on('poolStatus', function(status) {
        pool.status = status;
        pool.isOk = status.ok==1?"ok":"fault";
        pool.airTemp = status.airTemp;
        pool.waterTemp = status.currentTemp[0];
        pool.running = status.isPoolActive();
        pool.lightState = status.circuitArray[0].state==1?true:false;
        pool.highspeedState = status.circuitArray[1].state==1?true:false;
        node.status({fill:'green',shape:'dot',text:'connected, getting configuration'});
        this.getControllerConfig();
    }).on('controllerConfig', function(config) {
        node.status({fill:'green',shape:'dot',text: (pool.running?'running':'off') + ' ' + pool.waterTemp + pool.degreesUnit});
        pool.config=config;
        pool.degreesUnit = config.degC?"C":"F";
        pool.lightName = config.bodyArray[0].name;
        pool.highspeedName = config.bodyArray[1].name;
        pool.client = client;
        pool.remote = remote;
        node.status({fill:'green',shape:'dot',text:'connected, saving pool'});
        flow.set("pool", pool);
    }).on('loginFailed', function() {
        node.status({fill:'red',shape:'dot',text:'could not log in'});
        client.close();
    });
    client.connect();
  } else {
    node.status({fill:'red',shape:'dot',text:'no unit found by that name'});
    remote.close();
  }
 });

remote.connect();

return;

Can Intellibrite "save" and "recall" functionality from the mobile app be leveraged to store and set custom light colors?

@parnic @WhiteFire356 @bshep The iPhone app allows you to "save" the current color and hit the "recall" button to change all lights to that color. I use this to set the right color of blue that my wife likes as it fades through the various shades and hues. (pain in the ass to get it right) I assume it saves the RBG hex code for the current color value somewhere and loads it when the "recall" button is pressed.

It seems this would be a great was to create a custom color pallet of hex values (outside of pentair) and then pass in the desired RBG hex using whatever the "recall" feature uses.

Is this viable?

It would also be awesome if there was a way to dim the lights.

Issue with Buffer Changes.

Hey Parnic! Hope you are well.
I saw that you added SLEquipmentConfigurationMessage and so I cloned down the latest to my test server to see if I can help make heads or tails of the arrays. That said... I also picked up, of course, the buffer changes you made a few weeks ago.

I am getting some errors that the functions aren't declared. I tried to follow through your code to see if I could find them but I am just not that familiar with it yet. This is what I am seeing...

/usr/lib/node_modules/node-screenlogic/messages/SLGetGatewayDataMessage.js:11
size = buf.readInt32LE(4) + 8;
^

TypeError: buf.readInt32LE is not a function
at new SLGetGatewayDataMessage (/usr/lib/node_modules/node-screenlogic/messages/SLGetGatewayDataMessage.js:11:18)
at RemoteLogin.onConnected (/usr/lib/node_modules/node-screenlogic/index.js:87:23)
at Socket. (/usr/lib/node_modules/node-screenlogic/index.js:80:13)
at Object.onceWrapper (events.js:299:28)
at Socket.emit (events.js:215:7)
at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1115:10)

Talking to screen logic

Hey there,
I'm not sure if you want to have discussions like this over GitHub issues or else where but let me know if this should be some where else.

I recently had a new pool installed that has a pentair screen logic, intellibrite( lights ), intellichem and I also have my backyard lights wired into a relay.

I'd love to be able to talk to the system to both read and change state ( turning off water features, turn on lights, turn on the high speed circuit...ect)

Ideally I would be able to integrate into into my home automation (https://www.home-assistant.io/).

So questions:

  1. I see that I can read a bunch of data but am I able to turn on circuits?

Integration with nodejs-poolController

Hey @parnic! This is long overdue, but I'm finally at a place where I can integrate direct Screenlogic control into nodejs-poolController. I've been wanting to dig into this for quite a while.

To that end, I've gone through and converted all of your code to Typescript + Promises. It still supports the events, too. I've published this up to my repo at https://github.com/tagyoureit/node-screenlogic/tree/typescript. I've changed quite a bit (event names, data structure, return values, etc etc). I can keep this as a separate repo if that makes more sense. I haven't updated the docs yet but the example.ts shows how to use all of the methods.

First question is whether or not you are ok with moving to Typescript + Promises or you would rather keep the plain 'ole Javascript.

Second question is do you have any bandwidth to flush out more of the commands?

I'll also be able to help debugging/decoding many of the other aspects as I've got in-depth knowledge of how the RS485 packets work.

I've got a short list of items that I've compiled so far, but haven't gone through everything to validate it yet. Need to put it through a fine tooth comb.

  1. Equipment config - I see you have a separate thread on this... will try to dig into what I can find.
  2. Do you know how often a ping needs to be sent to keep a connection to the server?
  3. What's the difference between the clientId and senderId?
  4. I'm getting bad parameters trying to run the following: set circuit state, set circuit run time, delete schedule by id, set schedule
  5. 12504 is async message that the intellibrite is changing colors (~16s)
  6. I have not yet tested the local connection; I'm currently working remotely and also need to replace a fried chip on my transceiver

Heater/thermostat support?

Thank you for creating this! I've got everything working including spa and pool temp display, but I seem to not be able to turn the heater on/off or adjust the pool or spa temperature.

ECONNREFUSED on connect

First of all, this library is great! I've been working on a little smart dashboard for various things at our house and have had this plumbed in for a while now going back to last year when we had our pool put in. Things have been working with little issue until earlier this week and now I'm having a tough time getting connectivity to the pump. Base connection attempts are erroring out with the below:

Error: connect ECONNREFUSED 127.0.0.1
    at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1145:16) {
  errno: -111,
  code: 'ECONNREFUSED',
  syscall: 'connect',
  address: '127.0.0.1'
}

We still have connectivity via the mobile apps but I'm a little stumped as to what has changed. I verified that the credentials are still the same so just curious if you've got any insight or if anyone else may have experienced this.

Thanks!

The requested platform "ScreenLogic" was not registered by any plugin v2.0.1

Hi, I just stumbled across this great plugin and tried to get it setup in HOOBS. I have several other plugins working with HOOBS, however the ScreenLogic plugin fails with this message:

6/24/2020, 9:23:02 AM Loaded plugin "homebridge-screenlogic".
6/24/2020, 9:23:02 AM The requested platform "ScreenLogic" was not registered by any plugin.
6/24/2020, 9:23:02 AM Your config.json is requesting the platform "ScreenLogic" which has not been published by any installed plugins.

My config:
{
"platform": "ScreenLogic",
"plugin_map": {
"plugin_name": "homebridge-screenlogic"
},
"hidePoolTemperatureSensor": false,
"hideSpaTemperatureSensor": false,
"hideAirTemperatureSensor": false,
"hidePoolThermostat": false,
"hideSpaThermostat": false,
"statusPollingSeconds": 60
}

HOOBS 3.2.6 (up to date)
Node 12.16.2

Any ideas?

Decoding SLEquipmentConfigurationMessage

@mikemucc @bshep @tomblevins
Figured I'd go ahead and make an issue for decoding this thing so nobody's duplicating work.

As a reminder, most of this is coming from decompiling the slconfig app with jadx + experimentation.

  • versionDataArray can be turned into a version integer like so: (this.versionDataArray[0] * 1000) + (this.versionDataArray[1])
  • controllerData's top 2 bits indicate how many "slave" devices there are (which I'm calling "secondary" devices): (this.controllerData & 0x11000000) >> 6. don't know about the rest of the bits (my controller returns a value of 2 for this)
  • flowDataArray is where I've found the most interesting info so far. This contains information for up to 8 pumps worth of flow data. 45 bits are reserved for each pump and 24 of those contain data for the up-to-8 circuits that each pump supports. I've decoded a given pump's bits like this so far (values are from my equipment):
0:128 128 if pump exists, 0 if no pump, i think
1:0  priming time (in minutes, 0-10)
2:2  pump type (0 = none, 1 = IntelliFloVF, 2 = IntelliFloVS, 3 = IntelliFloVSF)
3:0  ? (maybe "background filtering"? this option is grayed out for me in slconfig)
4:11 circuit id (for me this is my "floor cleaner" circuit)
5:12 circuit val upper 8 bits
6:6  circuit id (for me this is "pool")
7:10 circuit val upper 8 bits
8:1  circuit id (for me this is "spa")
9:11 circuit val upper 8 bits
10:0 circuit id
11:3 circuit val upper 8 bits
12:0 circuit id
13:3 circuit val upper 8 bits
14:0 circuit id
15:3 circuit val upper 8 bits
16:0 circuit id
17:3 circuit val upper 8 bits
18:0 circuit id
19:3 circuit val upper 8 bits
20:3 priming RPM upper 8 bits
21:28 circuit 1 (4) val lower 8 bits
22:90 circuit 2 (6) val lower 8 bits
23:184 circuit 3 (8) val lower 8 bits
24:232 circuit 4 (10) val lower 8 bits
25:232 circuit 5 (12) val lower 8 bits
26:232 circuit 6 (14) val lower 8 bits
27:232 circuit 7 (16) val lower 8 bits
28:232 circuit 8 (18) val lower 8 bits
29:232 priming RPM lower 8 bits
30:0 unused?
31:0 unused?
32:0 unused?
33:0 unused?
34:0 unused?
35:0 unused?
36:0 unused?
37:0 unused?
38:0 unused?
39:0 unused?
40:0 unused?
41:0 unused?
42:0 unused?
43:0 unused?
44:0 unused?

Circuit id's are decoded via SLControllerConfigMessage's bodyArray array, deviceId property.
The circuit and priming rpms are really strange with the upper and lower bits separated in the array. Valid values for RPMs is 400 - 3450 with the default value being 1000 (upper 8 bits = 3, lower 8 bits = 232).

I'm having trouble reconciling this information with what I'm seeing in the SLConfig code, though. PageIntelliFloPriming and PageIntelliFloFiltering are both doing things with the flow data array, but the indices they're using don't match up quite right with what I'm seeing from my equipment. Still working on all this.

feature request: Access "history" data

I would really like to access the data that shows up in "history" on the pentair screen logic app. Pool temp, spa temp, outdoor temp and heater running time. It also shows pool mode and spa mode.

maybe its easier if I monitor those myself continuously, but curious if it is easy to pull from the device. Also not sure how much data it stores.

thanks.

Differentiate the callback event for getScheduleData(0) vs (1)

I'd like to see a the calls for getScheduleData(0) to have a different callback event name than getScheduleData(1). If I call both of those functions sequentially, I never actually get the egg timer data.

Or, make getScheduleData() = getScheduleData(0) and getEggTimers() = getScheduleData(1) and give it a different callback event name.

Schedule Create/Delete is a very long operation (15-20 seconds)

TL;DR version: it looks like it's taking between 15-20 seconds for the Create New Schedule ID/Delete Schedule ID calls to successfully complete. I believe that this may be the reason I'm not seeing the ACKs on Create/Delete Schedule.

The Long Version:
I'm now keeping a Set() object with the IDs of all of the Schedule Events (daily & run once) that exist on the system so I can quickly check to see if it exists (and return a 404 if somebody tries to Update or Delete an event ID that doesn't exist). I update this set every time I poll the ScreenLogic for new data. That polling frequency is currently 5 seconds.

So I end up with an object that looks kinda like this:
{ 700, 701, 702, 703, 704 }

So, from the perspective my my REST API:

  1. Start up the API. The API does its initial data load and logs all of the Schedule Event IDs that currently exist on the system (console.log() the Set() object that is schedules.eventIds).
  2. I call the "create New Schedule Event" endpoint.
  3. I watch the API logs make the call back to the ScreenLogic to create a new Schedule Event
  4. My API Polls the ScreenLogic Device immediately after making the CreateSchedule call (Lets cal this T=0)
    3a. During that poll, the API prints all of the current Schedule Event IDs on the system again. This is currently still the same as in step 0.
  5. 5 seconds later, the API polls again (Call this T=+5 seconds). The set of Schedule Event IDs on the system hasn't changed.
  6. Repeat Step 4 (Call this T+10)
  7. Repeat Step 4 (T+15)
  8. API Polls (T+20). Now the Schedule IDs on the system has incremented by 1 (i.e. the new schedule has actually been created).

So the apparent behavior is that a Create or Delete schedule event takes between 15 and 20 seconds to complete (at least on my system, the backend of which is an EasyTouch). This could be a result of my hardware, maybe the EasyTouch is a little slower than some of the other systems, who knows.

So I thought I remembered @bshep adding a keepalive value to the client. Could this be related to the behavior I'm seeing?

I could modify that line in my local cache to something like this.client.setKeepAlive(true, 25 * 1000); and see if it affects the behavior I'm seeing (if you think that would have any affect).

(Some) equipFlags meanings

Not so much an issue, but interesting findings that I thought anybody working on this would find useful.

I'm in the middle of creating a UI in Angular, and needed the ability to programmatically determine the heater/cooler configuration so I did a little research with my EasyTouch/ScreenLogic II today to figure out what equipFlags really means.

Here are the results:

24: No Solar (Heat Pump Present) - Baseline
25: Solar Present (+1)
27: Solar Is Heat Pump (+2)
27: UltraTemp or ThermaFlo (Turns on Solar & Solar Is Heat Pump)
28: Chlorinator Present (+4)
29: Chlorinator + Solar 
31: Chlorinator + Solar is Heat Pump

--- Cooling Present
8219: Has Cooling (+8192 (Turns on Solar Present (+1), Solar Is HP (+2), UltraTemp or ThermaFlo))
8223: Has Cooling + Chlorinator Present (Turns on Solar Present, Solar Is HP, UltraTemp or ThermaFlo)

--- IntelliChem Present
32792: IntelliChem Present (+32768)
32793: IC + Solar
32795: IC + Solar + Solar Is heatpump
32796: IntelliChem + Chlorinator
32797: IntelliChem + Chlorinator + Solar
32799 : IntelliChem + Chlorinator + Solar + Solar is HP
40991 : IntelliChem + Chlorinator + Solar + Cooling

Binary Representations:

Setting Binary Notes
Heater 0000000000011000 Baseline
+ Solar 0000000000011001
+ Solar + Solar is HP 0000000000011011
+ Chlorinator 0000000000011100
+ Chlorinator + Solar 0000000000011101
+ Ch + So + SoisHP 0000000000011111
+ Cooling (+ So + SoisHP) 00100000011011
+ Cooling + Ch 00100000011111
IntelliChem + Ch + Cooling + Solar 1010000000011111

Set pump speeds

Creating a new issue so we don't pollute the other thread.

When I get back the pump status the data is this:

Pump 0: 
{"pumpCircuits":
[
{"circuitId":1,"speed":5,"isRPMs":true},
{"circuitId":6,"speed":2000,"isRPMs":true},
{"circuitId":7,"speed":2500,"isRPMs":true},
{"circuitId":8,"speed":3250,"isRPMs":true},
{"circuitId":18,"speed":1320,"isRPMs":true},
{"circuitId":0,"speed":1000,"isRPMs":true},
{"circuitId":0,"speed":1000,"isRPMs":true},
{"circuitId":0,"speed":1000,"isRPMs":true}
],
"pumpType":2,
"isRunning":true,
"pumpWatts":506,
"pumpRPMs":2000,
"pumpUnknown1":0,
"pumpGPMs":255,
"pumpUnknown2":255}

I tried both (in your original code):

  • this.setPumpFlow(0,5,1010,true); (for the 5th index in the array)
  • this.setPumpFlow(0,18,1010,true); (for the circuit id of 18)

Neither worked. What am I missing here?

And a follow on item- looks like in order to change the pump, or circuit itself, I'll need to call 12568 and update the entire pool config. Does that sound correct?

Is UDP Broadcast the same as mdns/dns service discovery?

Hello still kinda new to node and networking. I'm working on something where I can search do dns service discovery and I can find local devices on my network by searching for _http._tcp. But im not sure how to search via dns service discovery for screenlogic. any pointers?

Unknown message 8300

When adding, setting, or deleting a schedule, I often get an 8300 response, but not the ack I expected.

2020-07-01T00:00:48.721Z sl:unit sending set schedule event command for scheduleId: 702, circuitId: 505, startTime: 420, stopTime: 1080, dayMask: 32, flags: 0, heatCmd: 0, heatSetPoint: 0...
2020-07-01T00:00:48.854Z sl:unit received message of length 12
2020-07-01T00:00:48.854Z sl:unit   it's an unknown type: 8300

The message buffer for 8300 is always the same

{
  "type": "Buffer",
  "data": [
    255,
    127,
    108,
    32,
    4,
    0,
    0,
    0,
    1,
    0,
    0,
    0
  ]
}

When I get 8300, I do not usually receive the response I expect (eg. delete ack, set ack, add ack)

2020-07-01T15:48:26.382Z sl:unit sending delete schedule event command for scheduleId: 702...
2020-07-01T15:48:26.489Z sl:unit received message of length 12
2020-07-01T15:48:26.490Z sl:unit   it's an unknown type: 8300

Occasionally I receive both 8300 and the response I expect

2020-07-01T15:48:26.382Z sl:unit sending delete schedule event command for scheduleId: 702...
2020-07-01T15:48:26.489Z sl:unit received message of length 12
2020-07-01T15:48:26.490Z sl:unit   it's an unknown type: 8300
2020-07-01T15:48:26.494Z sl:unit received message of length 8
2020-07-01T15:48:26.494Z sl:unit   it's a delete schedule event ack 12547

Sometimes I receive 8300 multiple times for one operation

2020-07-01T15:48:26.382Z sl:unit sending delete schedule event command for scheduleId: 702...
2020-07-01T15:48:26.489Z sl:unit received message of length 12
2020-07-01T15:48:26.490Z sl:unit   it's an unknown type: 8300
2020-07-01T15:48:26.493Z sl:unit received message of length 12
2020-07-01T15:48:26.494Z sl:unit   it's an unknown type: 8300

The operation always works, when I check getScheduleData, the schedule has been added/deleted/set, even though I didn't get a response.

Any ideal what message 8300 might be? Any suggestions for how I can figure out what it means, and why I'm seeing this behaviour?

Thanks!

Timeout / Parameter Failure on setCircuitAsync

Hello and thanks so much for putting this library together! Really amazing work!

I am attempting to turn a circuit on and getting a timeout: (I used getAllCircuitNamesAsync to look up the circuitId)

client.circuits.setCircuitStateAsync(72, 1)

The timeout error result I think might be a red herring though as I see the following in the debug logs:

  sl:unit [0] sending set circuit state command: controllerId: 0, circuitId: 72, circuitState: 1... +0ms
  sl:unit received 31 message of length 8 +9ms
  sl:unit   it is a parameter failure. +0ms

I've tried multiple circuits with the same result. I've also tried using both the local and remote connection approaches but this does not appear to make a difference. I am however able to successfully turn the pool light on and off using sendLightCommandAsync so I know that at some level things are working.

I checked the version of my equipment using getVersionAsync:

POOL: 5.2 Build 736.0 Rel

This isn't the latest version of the firmware but it is a version listed in this project's notes as one of the tested versions. Having said that I am wondering if maybe this version is only partially supported? I'd update my firmware but I am on a Mac and the screenlogic firmware updater unfortunately doesnt work on any remotely recent version of the Mac OS.

Any ideas what might be going on?

Server crashes out

Firstly, thank you so much for this code. I have set everything up and I am assuming that I run example.js? When i run it, it does connect to my unit but then exits with: controller is in celsius=false because of the client.close(). How do I keep this running? If I comment out that line, it runs for a little while and then crashes after a few seconds with:
Error: read ECONNRESET
at TCP.onStreamRead (internal/stream_base_commons.js:111:27)
Emitted 'error' event at:
at emitErrorNT (internal/streams/destroy.js:91:8)
at emitErrorAndCloseNT (internal/streams/destroy.js:59:3)
at process._tickCallback (internal/process/next_tick.js:63:19)

Lights Command questions

In the README it lists a bunch of light commands, but says that the command takes an Integer. Is this the correct mapping?

Edit: Correct Integers per below.

Number Meaning
0 ScreenLogic.LIGHT_CMD_LIGHTS_OFF
1 ScreenLogic.LIGHT_CMD_LIGHTS_ON
2 ScreenLogic.LIGHT_CMD_COLOR_SET
3 ScreenLogic.LIGHT_CMD_COLOR_SYNC
4 ScreenLogic.LIGHT_CMD_COLOR_SWIM
5 ScreenLogic.LIGHT_CMD_COLOR_MODE_PARTY
6 ScreenLogic.LIGHT_CMD_COLOR_MODE_ROMANCE
7 ScreenLogic.LIGHT_CMD_COLOR_MODE_CARIBBEAN
8 ScreenLogic.LIGHT_CMD_COLOR_MODE_AMERICAN
9 ScreenLogic.LIGHT_CMD_COLOR_MODE_SUNSET
10 ScreenLogic.LIGHT_CMD_COLOR_MODE_ROYAL
11 ScreenLogic.LIGHT_CMD_COLOR_SET_SAVE
12 ScreenLogic.LIGHT_CMD_COLOR_SET_RECALL
13 ScreenLogic.LIGHT_CMD_COLOR_BLUE
14 ScreenLogic.LIGHT_CMD_COLOR_GREEN
16 ScreenLogic.LIGHT_CMD_COLOR_RED
17 ScreenLogic.LIGHT_CMD_COLOR_WHITE
18 ScreenLogic.LIGHT_CMD_COLOR_PURPLE

getPumpStatus returns the same values regardless of pumpID passed

When I call getPumpStatus(pumpID) I get the same values coming back regardless of the pumpID I use. It is possible I am doing something wrong. Here is my example:

function connect(client) {
client.on('loggedIn', function() {
this.getVersion();
}).on('version', function(version) {
this.getSaltCellConfig();
}).on('saltCellConfig', function(saltCellConfig) {
this.getPumpStatus(0);
console.log('pentair/saltcellstatus/state,' + saltCellConfig.status);
console.log('pentair/saltcelllevel1/state,' + saltCellConfig.level1);
console.log('pentair/saltcelllevel2/state,' + saltCellConfig.level2);
}).on('getPumpStatus', function(status) {
this.getPumpStatus(2);
console.log('pentair/pump/0/watts/state,' + status.pumpWatts);
console.log('pentair/pump/0/rpm/state,' + status.pumpRPMs);
console.log('pentair/pump/0/gpm/state,' + status.pumpGPMs);
}).on('getPumpStatus', function(status) {
this.getPumpStatus(3);
console.log('pentair/pump/2/watts/state,' + status.pumpWatts);
console.log('pentair/pump/2/rpm/state,' + status.pumpRPMs);
console.log('pentair/pump/2/gpm/state,' + status.pumpGPMs);
}).on('getPumpStatus', function(status) {
this.getPumpStatus(4);
console.log('pentair/pump/3/watts/state,' + status.pumpWatts);
console.log('pentair/pump/3/rpm/state,' + status.pumpRPMs);
console.log('pentair/pump/3/gpm/state,' + status.pumpGPMs);
}).on('getPumpStatus', function(status) {
this.getPumpStatus(5);
console.log('pentair/pump/4/watts/state,' + status.pumpWatts);
console.log('pentair/pump/4/rpm/state,' + status.pumpRPMs);
console.log('pentair/pump/4/gpm/state,' + status.pumpGPMs);
}).on('getPumpStatus', function(status) {
this.getPumpStatus(6);
console.log('pentair/pump/5/watts/state,' + status.pumpWatts);
console.log('pentair/pump/5/rpm/state,' + status.pumpRPMs);
console.log('pentair/pump/5/gpm/state,' + status.pumpGPMs);
}).on('getPumpStatus', function(status) {
this.getPumpStatus(7);
console.log('pentair/pump/6/watts/state,' + status.pumpWatts);
console.log('pentair/pump/6/rpm/state,' + status.pumpRPMs);
console.log('pentair/pump/6/gpm/state,' + status.pumpGPMs);
}).on('getPumpStatus', function(status) {
this.getPumpStatus(1);
console.log('pentair/pump/7/watts/state,' + status.pumpWatts);
console.log('pentair/pump/7/rpm/state,' + status.pumpRPMs);
console.log('pentair/pump/7/gpm/state,' + status.pumpGPMs);
}).on('getPumpStatus', function(status) {
this.getPumpStatus(8);
console.log('pentair/pump/1/watts/state,' + status.pumpWatts);
console.log('pentair/pump/1/rpm/state,' + status.pumpRPMs);
console.log('pentair/pump/1/gpm/state,' + status.pumpGPMs);
}).on('getPumpStatus', function(status) {
console.log('pentair/pump/8/watts/state,' + status.pumpWatts);
console.log('pentair/pump/8/rpm/state,' + status.pumpRPMs);
console.log('pentair/pump/8/gpm/state,' + status.pumpGPMs);
client.close();
});

Also, how many pumps does ScreenLogic support? Is there any way to see how many pumps are installed with pumpIDs or do we just need to iterate through them to get details?

FEATURE: Set Timeout

Hey, really love the work here.

I'm writing an Alexa skill that controls various features and find that some are slower than others to respond with state confirmation. Would be super rad if we could set a config on the constructor to set a timeout vs. the default 2300ms.

RS-485?

Parnic,

Are you able to see what messages the RS-485 bus is sending/receiving? For example, I'm really interested in the ControllerConfigMessage and how it translates to a request/response on the serial bus. Let me know if you can see that side of the communications.

It's great you're making progress and I'm trying to understand how (or if) it makes sense to utilize this networking approach in my app.

Tag

Can't get example to run

Forgive this simple question as I've never used node.js before, but how do I run the example? I've downloaded the package as a zip file, expanded it, and edited example.js to use my systemName and password. But trying to run the example:

node-screenlogic$ node example.js 
/Users/colin/node.js/node-screenlogic/index.js:21
var remote = new ScreenLogic.RemoteLogin(systemName);
             ^

TypeError: ScreenLogic.RemoteLogin is not a constructor
    at Object.<anonymous> (/Users/colin/node.js/node-screenlogic/index.js:21:14)
    at Module._compile (internal/modules/cjs/loader.js:701:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:712:10)
    at Module.load (internal/modules/cjs/loader.js:600:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:539:12)
    at Function.Module._load (internal/modules/cjs/loader.js:531:3)
    at Module.require (internal/modules/cjs/loader.js:637:17)
    at require (internal/modules/cjs/helpers.js:22:18)
    at Object.<anonymous> (/Users/colin/node.js/node-screenlogic/example.js:3:21)
    at Module._compile (internal/modules/cjs/loader.js:701:30)
node-screenlogic$ 
node-screenlogic$ node -v
v10.15.3
node-screenlogic$

SLSetHeatSetPoint not parsing API response

Hi!

I'm using setSetPoint to set the temperature, and it's working fine -- but the emitted event doesn't parse the response from ScreenLogic so there's no way to programmatically verify the temperature was set correctly.

It looks like the messageId is different -- looking at the code SLSetHeatSetPoint expects message ID 12528, but the response I'm getting has 12529:

{"length":8,"_encoding":"utf8","_writeOffset":8,"_readOffset":8,"_buff":{"type":"Buffer","data":[0,0,241,48,0,0,0,0]},"_wroteSize":true,"senderId":0,"messageId":12529,"dataLength":0}

Is this just a matter of changing the messageId to get this parsed properly?

Question: Polling vs Listening for an event on poolStatus changes

Parnic, thank you for this piece of work. It's great. I'm using node-screenlogic + google to learn node.js (and programming in general) so apologies in advance if I'm missing the obvious.

I'm treating my pool (via node-screenlogic) as a series of sensors and publish their status in JSON format via mqtt.js. I'm also using mqtt to change the state of various components (pumps, spa temp, lights, etc.).

Currently, I'm polling the poolStatus and controllerConfig via setInterval to refresh and publish status. It's working, but it doesn't feel like the most efficient or stable approach.

Also note, most of my code is based on your example.js, node.js official docs and various node.js tutorials I've found via Google... so my approach is definitely a victim of the last tutorial I read.

Questions:

  • In this case is polling a valid strategy?
  • If not, Is there a status change event that I could listen for vs polling?
  • If so, do you happen to have additional code examples that might lead me down an appropriate path?

Eventually, I'd like to contribute a MQTT emitter to the project.

Thanks,
pgregg

CoolSetpoint on Spa tracks outdoor air temp?

I noticed today that the cool setpoint for a spa body (the data that comes back in SLPoolStatusMessage.js) seems to track along with the air temperature reading. At first I thought I had a bug somewhere parsing the data or updating my UI but when I look at the actual data coming back from the controller it matches what I see.

It probably makes sense in some way as a cool setpoint for a spa doesn't seem very useful but I thought I'd ask as I didn't see any reference to it in the code or docs that the controller would send back the air temp in the cool setpoint value for a spa. The pool setpoints (heat and cool) seem reasonable and I don't see them change as the air temp does.

Get current light color for pool/spa lights

I checked the SLControllerConfigMessage in bodyArray and colorArray, and I checked the SLPoolStatusMessage in circuit array. Am I missing something?

Also as a side question, is it possible to target specific group of lights, for example pool lights, or spa lights when doing sendLightCommand?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.