diff --git a/.snyk b/.snyk
index 6a931b1e..8db49efd 100644
--- a/.snyk
+++ b/.snyk
@@ -118,20 +118,23 @@ ignore:
'npm:bootstrap:20160627':
- bootstrap:
reason: None given
- expires: '2018-10-05T03:45:41.397Z'
+ expires: '2018-12-26T15:26:16.181Z'
'npm:lodash:20180130':
- snyk-go-plugin > graphlib > lodash:
reason: None given
expires: '2018-05-27T15:05:54.491Z'
- request-promise > request-promise-core > lodash:
+ node-ssdp > async > lodash:
reason: None given
- expires: '2018-11-13T23:00:17.087Z'
+ expires: '2019-02-03T00:16:15.673Z'
- node-ssdp > async > lodash:
reason: None given
- expires: '2018-04-01T03:18:10.568Z'
+ expires: '2018-12-26T15:26:16.181Z'
+ request-promise > request-promise-core > lodash:
+ reason: None given
+ expires: '2019-02-03T00:16:15.674Z'
- request-promise > request-promise-core > lodash:
reason: None given
- expires: '2018-04-01T03:18:10.569Z'
+ expires: '2018-12-26T15:26:16.181Z'
- node-ip > node-localip > wmic > async > lodash:
reason: None given
expires: '2018-04-01T03:18:10.568Z'
@@ -150,6 +153,12 @@ ignore:
- request-promise > request-promise-core > lodash:
reason: None given
expires: '2018-08-16T06:24:46.574Z'
+ - request-promise > request-promise-core > lodash:
+ reason: None given
+ expires: '2018-11-13T23:00:17.087Z'
+ - node-ip > node-localip > wmic > async > lodash:
+ reason: None given
+ expires: '2019-01-28T22:22:52.646Z'
'npm:hoek:20180212':
- request > hawk > hoek:
reason: None given
@@ -173,7 +182,7 @@ ignore:
'npm:extend:20180424':
- node-ssdp > extend:
reason: None given
- expires: '2018-11-13T23:00:17.087Z'
+ expires: '2019-01-28T22:22:52.645Z'
- request > extend:
reason: None given
expires: '2018-08-23T22:44:40.819Z'
@@ -199,7 +208,7 @@ ignore:
'npm:chownr:20180731':
- serialport > prebuild-install > tar-fs > chownr:
reason: None given
- expires: '2018-10-05T03:45:29.603Z'
+ expires: '2019-01-28T22:18:22.043Z'
- chokidar > fsevents > node-pre-gyp > tar > chownr:
reason: None given
expires: '2018-09-01T14:44:44.769Z'
diff --git a/README.md b/README.md
index 8eba71a3..44b6b742 100755
--- a/README.md
+++ b/README.md
@@ -1,21 +1,20 @@
-# nodejs-poolController - Version 5.2.0
+
+# nodejs-poolController - Version 5.3.0
+
[![Join the chat at https://gitter.im/nodejs-poolController/Lobby](https://badges.gitter.im/nodejs-poolController/Lobby.svg)](https://gitter.im/nodejs-poolController/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Build Status](https://travis-ci.org/tagyoureit/nodejs-poolController.svg?branch=master)](https://travis-ci.org/tagyoureit/nodejs-poolController) [![Coverage Status](https://coveralls.io/repos/github/tagyoureit/nodejs-poolController/badge.svg?branch=master)](https://coveralls.io/github/tagyoureit/nodejs-poolController?branch=master) [![Known Vulnerabilities](https://snyk.io/test/github/tagyoureit/nodejs-poolcontroller/badge.svg)](https://snyk.io/test/github/tagyoureit/nodejs-poolcontroller)
[Full Changelog](#module_nodejs-poolController--changelog)
-### 5.2.0
-1. Node 6+ is supported. This app no longer supports Node 4.
-1. Update of modules. Make sure to run `npm i` or `npm upgrade` to get the latest.
-1. Much better support of multiple Intellibrite controllers. We can read both controllers now. There are still some issues with sending changes and help is needed to debug these.
-1. Chlorinator API calls (and UI) will now make changes through Intellitouch when available, or directly to the Intellichlor if it is standalone (aka using the virtual controller)
-1. Decoupled serial port and processing of packets. Should help recovery upon packet errors.
-1. Implementation of #89. Expansion boards are now (better) supported by setting variables in your config.json. See the [config.json](#module_nodejs-poolController--config) section below.
-1. Fix for #95
-1. Fix for #99
-1. Fix for #100
+
+### 5.3.0
+1. Fix for #106
+1. Fix for "Error 60" messages
+1. Improved caching of files on browsers. Thanks @arrmo! Now files will be loaded once in the browser and kept in cache instead of reloaded each time.
+1. Improved handling of sessions and graceful closing of the HTTP(s) servers.
+
# License
@@ -198,10 +197,14 @@ for discussions, designs, and clarifications, we recommend you join our [Gitter
#### Chlorinator and Intellichem
-
+(Note: As of 5.3 the Chlorinator API's will route the commands either through the Intellitouch/Intellicom or directly to the chlorinator depending upon your setup)
| Direction | Socket | API | Description |
| --- | --- | --- | --- |
-| To app | setchlorinator(level)
| /chlorinator/{level}
|sets the level of output for chlorinator (pool only)
+| To app | setchlorinator(poolLevel, spaLevel, superChlorinateHours)
| /chlorinator/{level}/spa/{level}/superChlorinateHours/{hours}
|sets the level of output for chlorinator (spa/superchlorinate can be omitted)
+| To app | | /chlorinator/pool/{level}
|sets the pool output %
+| To app | | /chlorinator/spa/{level}
|sets the spa output %
+| To app | | /chlorinator/pool/{level}/spa/{level}
|sets the pool & spa output %
+| To app | | /chlorinator/superChlorinateHours/{hours}
|sets the hours for super chlorination
| To client | chlorinator
| outputs an object with the chlorinator information
| To app | | /chlorinator
| outputs an object with the chlorinator information
| To app | intellichem
| /intellichem
|outputs an object with the intellichem information
@@ -947,7 +950,16 @@ See the constants.js file and the sections:
1. Started to move some of the inter-communications to emitter events for better micro-services and shorter call stacks (easier debugging; loosely coupled code).
1. Changed some Influx tags/queries.
-
+### 5.2.0
+1. Node 6+ is supported. This app no longer supports Node 4.
+1. Update of modules. Make sure to run `npm i` or `npm upgrade` to get the latest.
+1. Much better support of multiple Intellibrite controllers. We can read both controllers now. There are still some issues with sending changes and help is needed to debug these.
+1. Chlorinator API calls (and UI) will now make changes through Intellitouch when available, or directly to the Intellichlor if it is standalone (aka using the virtual controller)
+1. Decoupled serial port and processing of packets. Should help recovery upon packet errors.
+1. Implementation of #89. Expansion boards are now (better) supported by setting variables in your config.json. See the [config.json](#module_nodejs-poolController--config) section below.
+1. Fix for #95
+1. Fix for #99
+1. Fix for #100
diff --git a/package.json b/package.json
index c888ef38..16c77b42 100644
--- a/package.json
+++ b/package.json
@@ -41,16 +41,17 @@
},
"homepage": "https://github.com/tagyoureit/nodejs-poolController#readme",
"dependencies": {
- "bluebird": "^3.5.0",
- "bootstrap": "^3.3.7",
+ "bluebird": "^3.5.3",
+ "bootstrap": "^3.4.0",
"bottlejs": "^1.7.1",
"dateformat": "^3.0.3",
"deep-diff": "^1.0.1",
"dequeue": "^1.0.5",
"events": "^3.0.0",
- "express": "^4.16.3",
+ "express": "^4.16.4",
"getmac": "^1.4.3",
"http-auth": "^3.1.3",
+ "http-shutdown": "^1.2.0",
"influx": "^5.0.7",
"ip": "^1.1.5",
"jquery": "^3.2.1",
@@ -65,24 +66,24 @@
"request": "^2.87.0",
"request-promise": "^4.2.2",
"serialport": "^6.2.2",
- "socket.io": "^2.1.1",
- "socket.io-client": "^2.1.1",
+ "socket.io": "^2.2.0",
+ "socket.io-client": "^2.2.0",
"underscore": "^1.9.1",
"winston": "^2.4.3",
- "winston-transport": "^4.2.0",
+ "winston-transport": "^4.3.0",
"yargs-parser": "^10.1.0"
},
"devDependencies": {
- "chai": "^4.0.1",
- "coveralls": "^3.0.1",
+ "chai": "^4.2.0",
+ "coveralls": "^3.0.2",
"grunt": "^1.0.3",
"grunt-banner": "^0.6.0",
"istanbul": "^0.4.5",
- "jshint": "^2.9.4",
+ "jshint": "^2.9.7",
"mocha": "^5.2.0",
"nock": "^9.3.3",
"sinon": "^6.1.4",
- "snyk": "^1.83.0"
+ "snyk": "^1.120.1"
},
"snyk": true
}
diff --git a/specs/assets/config/config.json b/specs/assets/config/config.json
index bbf0b517..1d2b424b 100644
--- a/specs/assets/config/config.json
+++ b/specs/assets/config/config.json
@@ -1,5 +1,16 @@
{
- "version": "5.2.0",
+ "meta": {
+ "notifications": {
+ "version": {
+ "remote": {
+ "version": "4.1.200",
+ "tag_name": "v4.1.200",
+ "dismissUntilNextRemoteVersionBump": false
+ }
+ }
+ }
+ },
+ "version": "5.3.0",
"equipment": {
"controller": {
"intellicom": {
@@ -141,16 +152,5 @@
}
}
},
- "meta": {
- "notifications": {
- "version": {
- "remote": {
- "version": "4.0.0",
- "tag_name": "v4.0.0",
- "dismissUntilNextRemoteVersionBump": false
- }
- }
- }
- },
"integrations": {}
}
\ No newline at end of file
diff --git a/specs/assets/replays/1/config.json b/specs/assets/replays/1/config.json
index 6fb0978f..3e8a7dfb 100644
--- a/specs/assets/replays/1/config.json
+++ b/specs/assets/replays/1/config.json
@@ -1,5 +1,5 @@
{
- "version": "5.2.0",
+ "version": "5.3.01",
"equipment": {
"controller": {
"intellicom": {
@@ -292,4 +292,4 @@
"integrations": {
"outputToNodeRED": 1
}
-}
+}
\ No newline at end of file
diff --git a/specs/assets/replays/1/packetCapture.json b/specs/assets/replays/1/packetCapture.json
index 031a0604..79199a03 100644
--- a/specs/assets/replays/1/packetCapture.json
+++ b/specs/assets/replays/1/packetCapture.json
@@ -606,4 +606,4 @@
{"type":"packet","packet":[255,255,255,255,255,255,255,255,0,255,165,1,15,16,2,29,15,10,2,0,0,0,0,0,0,4,64,0,0,0,26,26],"direction":"inbound","level":"info","message":"","timestamp":"2018-08-01T19:11:22.818Z"}
{"type":"packet","packet":[0,0,27,0,0,0,0,4,0,0,0,1,3,1,154],"direction":"inbound","level":"info","message":"","timestamp":"2018-08-01T19:11:22.840Z"}
{"type":"packet","packet":[255,255,255,255,255,255,255,255,0,255,165,1,15,16,2,29,15,10,2,0,0,0,0,0,0,4,64,0,0,0,26,26],"direction":"inbound","level":"info","message":"","timestamp":"2018-08-01T19:11:24.774Z"}
-{"type":"packet","packet":[0,0,27,0,0,0,0,4,0,0,0,1,3,1,154],"direction":"inbound","level":"info","message":"","timestamp":"2018-08-01T19:11:24.796Z"}
+{"type":"packet","packet":[0,0,27,0,0,0,0,4,0,0,0,1,3,1,154],"direction":"inbound","level":"info","message":"","timestamp":"2018-08-01T19:11:24.796Z"}
\ No newline at end of file
diff --git a/specs/assets/replays/1/packetCapture.log b/specs/assets/replays/1/packetCapture.log
index efa6177c..59a97a35 100644
--- a/specs/assets/replays/1/packetCapture.log
+++ b/specs/assets/replays/1/packetCapture.log
@@ -9,11 +9,11 @@
15:09:47.871 INFO Settings:
*******************************
- Version: 5.2.0
+ Version: 5.3.01
Configuration file name: config.json
*******************************{
- "version": "5.2.0",
+ "version": "5.3.01",
"equipment": {
"controller": {
"intellicom": {
@@ -326,7 +326,7 @@ Configuration file name: config.json
15:09:47.974 SILLY New SOCKET.IO Client connected, rN_W8cd9yhLJ_2KjAAAA
15:09:47.975 SILLY Outputting socket all
15:09:47.975 SILLY Socket.IO checking if we need to output updateAvail: false (will send if false)
-15:09:47.979 SILLY Socket.IO NOT outputting updateAvail because it is missing the result string: {"local":{"version":"5.2.0"}}
+15:09:47.979 SILLY Socket.IO NOT outputting updateAvail because it is missing the result string: {"local":{"version":"5.3.01"}}
15:09:47.987 SILLY New https server connection ::ffff:127.0.0.1
15:09:47.988 SILLY New https server connection ::ffff:127.0.0.1
15:09:48.000 VERBOSE Sending NR POST
@@ -343,12 +343,12 @@ Configuration file name: config.json
15:09:48.134 SILLY updateAvail.compareLocaltoSavedLocal: (current) published release (5.1.1) to cached/last published config.json version (5.1.1)
15:09:48.134 SILLY updateAvail: no change in current remote version compared to local cached config.json version of app
15:09:48.136 SILLY updateAvail: versions discovered:
- {"local":{"version":"5.2.0"},"remote":{"tag_name":"v5.1.1","version":"5.1.1"}}
-15:09:48.137 SILLY updateAvail: local ver: 5.2.0 latest published release ver: 5.1.1
-15:09:48.139 INFO You are running a newer release (5.2.0) than the published release (5.1.1)
+ {"local":{"version":"5.3.01"},"remote":{"tag_name":"v5.1.1","version":"5.1.1"}}
+15:09:48.137 SILLY updateAvail: local ver: 5.3.01 latest published release ver: 5.1.1
+15:09:48.139 INFO You are running a newer release (5.3.01) than the published release (5.1.1)
15:09:48.140 SILLY Outputting socket updateAvailable
15:09:48.141 SILLY Socket.IO checking if we need to output updateAvail: false (will send if false)
-15:09:48.141 SILLY Socket.IO outputting updateAvail: {"local":{"version":"5.2.0"},"remote":{"tag_name":"v5.1.1","version":"5.1.1"},"result":"newer","resultStr":"You are running a newer release (5.2.0) than the published release (5.1.1)"}
+15:09:48.141 SILLY Socket.IO outputting updateAvail: {"local":{"version":"5.3.01"},"remote":{"tag_name":"v5.1.1","version":"5.1.1"},"result":"newer","resultStr":"You are running a newer release (5.3.01) than the published release (5.1.1)"}
15:09:48.142 SILLY updateAvail: finished successfully
15:09:48.163 VERBOSE ISY: Response from ISY: [object Object]
views: ' + req.session.views + '
') + res.write('expires in: ' + (req.session.cookie.maxAge / 1000) + 's
') + res.write('json session:
' + JSON.stringify(req.session) )
+ res.end()
+ } else {
+ req.session.views = 1
+ res.end('welcome to the session demo. refresh!')
+ }
+
+ //output request variables
+ console.log(`Request session: ${req}`)
+ */
next()
})
// Routing
- app.use(express.static(path.join(process.cwd(), 'src/www')));
- app.use('/bootstrap', express.static(path.join(process.cwd(), '/node_modules/bootstrap/dist/')));
- app.use('/jquery', express.static(path.join(process.cwd(), '/node_modules/jquery/')));
- app.use('/jquery-ui', express.static(path.join(process.cwd(), '/node_modules/jquery-ui-dist/')));
- app.use('/jquery-clockpicker', express.static(path.join(process.cwd(), '/node_modules/jquery-clockpicker/dist/')));
+ app.use(express.static(path.join(process.cwd(), 'src/www'), { maxAge: '14d' }));
+ app.use('/bootstrap', express.static(path.join(process.cwd(), '/node_modules/bootstrap/dist/'), { maxAge: '60d' }));
+ app.use('/jquery', express.static(path.join(process.cwd(), '/node_modules/jquery/'), { maxAge: '60d' }));
+ app.use('/jquery-ui', express.static(path.join(process.cwd(), '/node_modules/jquery-ui-dist/'), { maxAge: '60d' }));
+ app.use('/jquery-clockpicker', express.static(path.join(process.cwd(), '/node_modules/jquery-clockpicker/dist/'), { maxAge: '60d' }));
+ app.use('/socket.io-client', express.static(path.join(process.cwd(), '/node_modules/socket.io-client/dist/'), { maxAge: '60d' }));
+
// disable for security
app.disable('x-powered-by')
@@ -322,6 +334,8 @@ module.exports = function (container) {
res.send(container.status.getCurrentStatus())
})*/
+
+
app.get('/all', function (req, res) {
res.send(container.helpers.allEquipmentInOneJSON());
container.io.emitToClients('all');
@@ -471,7 +485,7 @@ module.exports = function (container) {
})
-//TODO: do we need DOW in these???
+ //TODO: do we need DOW in these???
app.get('/datetime/set/time/:hh/:mm/date/:dow/:dd/:mon/:yy/:dst', function (req, res) {
var hour = parseInt(req.params.hh)
var min = parseInt(req.params.mm)
@@ -537,6 +551,7 @@ module.exports = function (container) {
res.send(container.intellichem.getCurrentIntellichem())
})
+ // This should be deprecated
app.get('/chlorinator/:chlorinateLevel', function (req, res) {
container.chlorinator.setChlorinatorLevelAsync(parseInt(req.params.chlorinateLevel))
.then(function (response) {
@@ -544,6 +559,43 @@ module.exports = function (container) {
})
})
+ app.get('/chlorinator/pool/:poolChlorinateLevel', function (req, res) {
+ container.chlorinator.setChlorinatorLevelAsync(parseInt(req.params.poolChlorinateLevel))
+ .then(function (response) {
+ res.send(response)
+ })
+ })
+
+ app.get('/chlorinator/spa/:spaChlorinateLevel', function (req, res) {
+ container.chlorinator.setChlorinatorLevelAsync(-1, parseInt(req.params.spaChlorinateLevel))
+ .then(function (response) {
+ res.send(response)
+ })
+ })
+
+ app.get('/chlorinator/pool/:poolChlorinateLevel/spa/:spaChlorinateLevel', function (req, res) {
+ container.chlorinator.setChlorinatorLevelAsync(parseInt(req.params.poolChlorinateLevel), parseInt(req.params.spaChlorinateLevel))
+ .then(function (response) {
+ res.send(response)
+ })
+ })
+
+
+ app.get('/chlorinator/superChlorinateHours/:hours', function (req, res) {
+ container.chlorinator.setChlorinatorLevelAsync(-1, -1, parseInt(req.params.hours))
+ .then(function (response) {
+ res.send(response)
+ })
+ })
+
+ app.get('/chlorinator/pool/:poolChlorinateLevel/spa/:spaChlorinateLevel/superChlorinateHours/:hours', function (req, res) {
+ container.chlorinator.setChlorinatorLevelAsync(parseInt(req.params.poolChlorinateLevel), parseInt(req.params.spaChlorinateLevel), parseInt(req.params.hours))
+ .then(function (response) {
+ res.send(response)
+ })
+ })
+
+
app.get('/light/mode/:mode', function (req, res) {
if (parseInt(req.params.mode) >= 0 && parseInt(req.params.mode) <= 256) {
res.send(container.circuit.setLightMode(parseInt(req.params.mode)))
@@ -862,7 +914,7 @@ module.exports = function (container) {
res.send(response)
})
-//#11 Run pump at GPM for an indefinite duration
+ //#11 Run pump at GPM for an indefinite duration
app.get('/pumpCommand/run/pump/:pump/gpm/:gpm', function (req, res) {
var pump = parseInt(req.params.pump)
var gpm = parseInt(req.params.gpm)
@@ -876,7 +928,7 @@ module.exports = function (container) {
res.send(response)
})
-//#12 Run pump at GPM for specified duration
+ //#12 Run pump at GPM for specified duration
app.get('/pumpCommand/run/pump/:pump/gpm/:gpm/duration/:duration', function (req, res) {
var pump = parseInt(req.params.pump)
var gpm = parseInt(req.params.gpm)
@@ -890,7 +942,7 @@ module.exports = function (container) {
res.send(response)
})
-//#13 Save program to pump
+ //#13 Save program to pump
app.get('/pumpCommand/save/pump/:pump/program/:program/gpm/:speed', function (req, res) {
var pump = parseInt(req.params.pump)
var program = parseInt(req.params.program)
@@ -911,7 +963,7 @@ module.exports = function (container) {
}
})
-//#14 Save and run program for indefinite duration
+ //#14 Save and run program for indefinite duration
app.get('/pumpCommand/saverun/pump/:pump/program/:program/gpm/:speed', function (req, res) {
var pump = parseInt(req.params.pump)
var program = parseInt(req.params.program)
@@ -930,7 +982,7 @@ module.exports = function (container) {
}
})
-//#15 Save and run program for specified duration
+ //#15 Save and run program for specified duration
app.get('/pumpCommand/saverun/pump/:pump/program/:program/gpm/:speed/duration/:duration', function (req, res) {
var pump = parseInt(req.params.pump)
diff --git a/src/lib/comms/socketio-helper.js b/src/lib/comms/socketio-helper.js
index 70278cb9..40bcadcb 100755
--- a/src/lib/comms/socketio-helper.js
+++ b/src/lib/comms/socketio-helper.js
@@ -197,7 +197,7 @@ module.exports = function (container) {
}
else {
try {
- container.logger.debug('Stopping Socket IO Server')
+ container.logger.debug(`Stopping Socket IO ${type} Server`)
while (socketList[type].length !== 0) {
container.logger.silly('total sockets in list: ', socketList[type].length)
@@ -212,7 +212,7 @@ module.exports = function (container) {
if (typeof io[type].close === 'function') {
io[type].close();
io[type + 'Enabled'] = 0
- container.logger.debug('Socket IO Server closed')
+ container.logger.debug(`Socket IO ${type} Server closed`)
}
else {
container.logger.silly('Trying to close IO server, but already closed.')
diff --git a/src/lib/equipment/chlorinator.js b/src/lib/equipment/chlorinator.js
index 5518b88d..a006e1cd 100755
--- a/src/lib/equipment/chlorinator.js
+++ b/src/lib/equipment/chlorinator.js
@@ -225,10 +225,61 @@ module.exports = function (container) {
container.chlorinatorController.startChlorinatorController()
}
+ let response = {}
+ if (currentChlorinatorStatus.controlledBy === 'virtual') {
+ // check for valid settings to be sent to Chlorinator directly
+ if (chlorPoolLvl >= 0 && chlorPoolLvl <= 101) {
+ currentChlorinatorStatus.outputPoolPercent = chlorPoolLvl
+ }
+ else {
+
+ response.text = 'FAIL: Request for invalid value for chlorinator (' + chlorPoolLvl + '). Chlorinator will continue to run at previous level (' + currentChlorinatorStatus.outputPoolPercent + ')'
+ response.status = this.status
+ response.value = currentChlorinatorStatus.outputPoolPercent
+ if (container.settings.get('logChlorinator')) {
+ container.logger.warn(response)
+ }
+ return Promise.resolve(response)
+ }
+ }
+ else {
+ // check for valid values with Intellicom/Intellitouch
+ if (chlorPoolLvl === 101) {
+ // assume we will set the superchlorinate for 1 hour
+ chlorSuperChlorinateHours = 1
+ }
+ else if (chlorPoolLvl >= 0 && chlorPoolLvl <= 100) {
+ currentChlorinatorStatus.outputPoolPercent = chlorPoolLvl
+ }
+ else {
+ if (!chlorPoolLvl || chlorPoolLvl < -1 || chlorPoolLvl > 101) {
+ // -1 is valid if we don't want to change the setting. Anything else is invalid and should trigger a fail.
+ currentChlorinatorStatus.outputPoolPercent = 0;
+ response.text = 'FAIL: Request for invalid value for chlorinator (' + chlorPoolLvl + '). Chlorinator will continue to run at previous level (' + currentChlorinatorStatus.outputPoolPercent + ')'
+ response.status = this.status
+ response.value = currentChlorinatorStatus.outputPoolPercent
+ response.chlorinator = currentChlorinatorStatus
+ if (container.settings.get('logChlorinator')) {
+ container.logger.warn(response)
+ }
+ return Promise.resolve(response)
+ }
+
+ }
+ }
+
+
if (chlorSpaLvl >= 0 & chlorSpaLvl <= 100) {
currentChlorinatorStatus.outputSpaPercent = chlorSpaLvl
}
- if (chlorSuperChlorinateHours > 0 & chlorSuperChlorinateHours <= 96) {
+ else {
+ if (!currentChlorinatorStatus.outputSpaPercent || currentChlorinatorStatus.outputSpaPercent < 0) {
+ // just in case it isn't set. otherwise we don't want to touch it
+ currentChlorinatorStatus.outputSpaPercent = 0;
+ }
+ }
+
+ if ((chlorSuperChlorinateHours > 0 & chlorSuperChlorinateHours <= 96) || currentChlorinatorStatus.superChlorinateHours>0) {
currentChlorinatorStatus.superChlorinate = 1
currentChlorinatorStatus.superChlorinateHours = chlorSuperChlorinateHours
}
@@ -236,112 +287,94 @@ module.exports = function (container) {
currentChlorinatorStatus.superChlorinate = 0
currentChlorinatorStatus.superChlorinateHours = 0
}
- currentChlorinatorStatus.outputPoolPercent = chlorPoolLvl
-
- let response = {}
- return Promise.resolve()
- .then(function () {
- if (container.settings.get('chlorinator.installed')) {
- if (currentChlorinatorStatus.controlledBy === 'virtual') {
- // chlorinator only has pool setting; send commands directly to chlorinator
- if (chlorPoolLvl >= 0 && chlorPoolLvl <= 101) {
- return Promise.resolve()
- .then(function () {
-
- if (currentChlorinatorStatus.outputPoolPercent === 0) {
- response.text = 'Chlorinator set to off. Chlorinator will be queried every 30 mins for PPM'
- response.status = 'off'
- response.value = 0
- } else if (currentChlorinatorStatus.outputPoolPercent >= 1 && currentChlorinatorStatus.outputPoolPercent <= 100) {
- response.text = 'Chlorinator set to ' + currentChlorinatorStatus.outputPoolPercent + '%.'
- response.status = 'on'
- response.value = currentChlorinatorStatus.outputPoolPercent
- } else if (currentChlorinatorStatus.outputPoolPercent === 101) {
- response.text = 'Chlorinator set to super chlorinate'
- response.status = 'on'
- response.value = currentChlorinatorStatus.outputPoolPercent
- }
- })
- .then(container.settings.updateChlorinatorDesiredOutputAsync(chlorPoolLvl, currentChlorinatorStatus.outputSpaPercent))
- .then(function () {
- container.io.emitToClients('chlorinator')
- if (container.chlorinatorController.isChlorinatorTimerRunning())
- container.chlorinatorController.chlorinatorStatusCheck() //This is causing problems if the chlorinator is offline (repeated calls to send status packet.)
- else
- container.queuePacket.queuePacket([16, 2, 80, 17, chlorPoolLvl])
- if (container.settings.get('logChlorinator')) {
- container.logger.info(response)
- }
- return response
- })
- }
- else {
- response.text = 'FAIL: Request for invalid value for chlorinator (' + chlorPoolLvl + '). Chlorinator will continue to run at previous level (' + currentChlorinatorStatus.outputPoolPercent + ')'
- response.status = this.status
+ if (container.settings.get('chlorinator.installed')) {
+ if (currentChlorinatorStatus.controlledBy === 'virtual') {
+ // chlorinator only has one setting; it doesn't know the difference between pool/spa
+ return Promise.resolve()
+ .then(function () {
+ response.chlorinator = currentChlorinatorStatus
+ if (currentChlorinatorStatus.outputPoolPercent === 0) {
+ response.text = 'Chlorinator set to off. Chlorinator will be queried every 30 mins for PPM'
+ response.status = 'off'
+ response.value = 0
+ } else if (currentChlorinatorStatus.outputPoolPercent >= 1 && currentChlorinatorStatus.outputPoolPercent <= 100) {
+ response.text = 'Chlorinator set to ' + currentChlorinatorStatus.outputPoolPercent + '%.'
+ response.status = 'on'
+ response.value = currentChlorinatorStatus.outputPoolPercent
+ } else if (currentChlorinatorStatus.outputPoolPercent === 101) {
+ response.text = 'Chlorinator set to super chlorinate'
+ response.status = 'on'
response.value = currentChlorinatorStatus.outputPoolPercent
- if (container.settings.get('logChlorinator')) {
- container.logger.warn(response)
- }
- return Promise.resolve(response)
}
- }
- else if (currentChlorinatorStatus.controlledBy === 'intellicom') {
- // chlorinator controlled by intellicom; it only has the pool setting
+ })
+ .then(container.settings.updateChlorinatorDesiredOutputAsync(currentChlorinatorStatus.outputPoolPercent, currentChlorinatorStatus.outputSpaPercent))
+ .then(function () {
+ container.io.emitToClients('chlorinator')
+ if (container.chlorinatorController.isChlorinatorTimerRunning())
+ container.chlorinatorController.chlorinatorStatusCheck() //This is causing problems if the chlorinator is offline (repeated calls to send status packet.)
+ else
+ container.queuePacket.queuePacket([16, 2, 80, 17, currentChlorinatorStatus.outputPoolPercent])
+ if (container.settings.get('logChlorinator')) {
+ container.logger.info(response)
+ }
+ return response
+ })
+ }
+
+ else if (currentChlorinatorStatus.controlledBy === 'intellicom') {
+ // chlorinator controlled by intellicom; it only has the pool setting
- return Promise.resolve()
- .then(function () {
+ return Promise.resolve()
+ .then(function () {
+ response.chlorinator = currentChlorinatorStatus
+ response.text = `Chlorinator set to ${currentChlorinatorStatus.outputPoolPercent} and SuperChlorinate is ${currentChlorinatorStatus.superChlorinate} for ${currentChlorinatorStatus.superChlorinateHours} hours.`
+ response.status = 'on'
+ response.value = currentChlorinatorStatus.outputPoolPercent
- if (chlorPoolLvl >= 0 && chlorPoolLvl <= 100) {
- currentChlorinatorStatus.outputPoolPercent = chlorPoolLvl
- response.text = `Chlorinator set to ${currentChlorinatorStatus.outputPoolPercent} and SuperChlorinate is ${currentChlorinatorStatus.superChlorinate} for ${currentChlorinatorStatus.superChlorinateHours} hours.`
- response.status = 'on'
- response.value = currentChlorinatorStatus.outputPoolPercent
- }
- })
- .then(container.settings.updateChlorinatorDesiredOutputAsync(currentChlorinatorStatus.outputPoolPercent, currentChlorinatorStatus.outputSpaPercent))
- .then(function () {
- container.queuePacket.queuePacket([165, container.intellitouch.getPreambleByte(), 16, container.settings.get('appAddress'), 153, 10, outputSpaByte(), currentChlorinatorStatus.outputPoolPercent, 0, superChlorinateByte(), 0, 0, 0, 0, 0, 0, 0])
+ })
+ .then(container.settings.updateChlorinatorDesiredOutputAsync(currentChlorinatorStatus.outputPoolPercent, currentChlorinatorStatus.outputSpaPercent))
+ .then(function () {
+ // TODO: Check if the packet is the same on Intellicom (sans Spa setting)... currently it is the same as Intellichlor but the response is formatted differently.
+ container.queuePacket.queuePacket([165, container.intellitouch.getPreambleByte(), 16, container.settings.get('appAddress'), 153, 10, outputSpaByte(), currentChlorinatorStatus.outputPoolPercent, 0, superChlorinateByte(), 0, 0, 0, 0, 0, 0, 0])
- })
+ })
+
+ if (container.settings.get('logChlorinator')) {
+ container.logger.info(response)
+ }
+ }
+ else {
+ // controlled by Intellitouch. We should set both pool and spa levels at the controller
+
+ return Promise.resolve()
+ .then(function () {
+ response.chlorinator = currentChlorinatorStatus
+ response.text = `Chlorinator pool set to ${currentChlorinatorStatus.outputPoolPercent}, spa set to ${currentChlorinatorStatus.outputSpaPercent} and SuperChlorinate is ${currentChlorinatorStatus.superChlorinate} for ${currentChlorinatorStatus.superChlorinateHours} hours.`
+ response.status = 'on'
+ response.value = currentChlorinatorStatus.outputPoolPercent
+
+ })
+ .then(container.settings.updateChlorinatorDesiredOutputAsync(currentChlorinatorStatus.outputPoolPercent, currentChlorinatorStatus.outputSpaPercent))
+ .then(function () {
+ container.queuePacket.queuePacket([165, container.intellitouch.getPreambleByte(), 16, container.settings.get('appAddress'), 153, 10, outputSpaByte(), currentChlorinatorStatus.outputPoolPercent, superChlorinateByte(), 0, 0, 0, 0, 0, 0, 0])
if (container.settings.get('logChlorinator')) {
container.logger.info(response)
}
- }
+ return response
+ })
- else {
- // controlled by Intellitouch. We should set both pool and spa levels at the controller
-
- return Promise.resolve()
- .then(function () {
-
- if (chlorPoolLvl >= 0 && chlorPoolLvl <= 100) {
- currentChlorinatorStatus.outputPoolPercent = chlorPoolLvl
- response.text = `Chlorinator pool set to ${currentChlorinatorStatus.outputPoolPercent}, spa set to ${currentChlorinatorStatus.outputSpaPercent} and SuperChlorinate is ${currentChlorinatorStatus.superChlorinate} for ${currentChlorinatorStatus.superChlorinateHours} hours.`
- response.status = 'on'
- response.value = currentChlorinatorStatus.outputPoolPercent
- }
- })
- .then(container.settings.updateChlorinatorDesiredOutputAsync(currentChlorinatorStatus.outputPoolPercent, currentChlorinatorStatus.outputSpaPercent))
- .then(function () {
- container.queuePacket.queuePacket([165, container.intellitouch.getPreambleByte(), 16, container.settings.get('appAddress'), 153, 10, outputSpaByte(), currentChlorinatorStatus.outputPoolPercent, superChlorinateByte(), 0, 0, 0, 0, 0, 0, 0])
- if (container.settings.get('logChlorinator')) {
- container.logger.info(response)
- }
- return Promise.resolve(response)
- })
+ }
+ container.io.emitToClients('chlorinator')
+ }
- }
- container.io.emitToClients('chlorinator')
- }
- else {
- // chlor NOT installed
- response.text = 'FAIL: Chlorinator not enabled. Set Chlorinator=1 in config.json'
- return Promise.resolve(response)
- }
- })
+ else {
+ // chlor NOT installed
+ response.text = 'FAIL: Chlorinator not enabled. Set Chlorinator=1 in config.json'
+ return Promise.resolve(response)
+ }
}
diff --git a/src/lib/equipment/circuit.js b/src/lib/equipment/circuit.js
index a763c191..67b450dd 100755
--- a/src/lib/equipment/circuit.js
+++ b/src/lib/equipment/circuit.js
@@ -949,6 +949,9 @@ module.exports = function (container) {
container.logger.info(retStr)
}
+ // assign color to circuit object
+ assignControllerLightColor(mode,0,'API')
+
return retStr
}
diff --git a/src/lib/logger/winston-3.js b/src/lib/logger/winston-3.js
index a27559ed..863ab368 100644
--- a/src/lib/logger/winston-3.js
+++ b/src/lib/logger/winston-3.js
@@ -174,13 +174,13 @@ module.exports = function (container) {
packetLogger.info(msg)
}
- function error(msg) {
- if (logger === undefined) {
- console.log('Error ', arguments)
- }
- else
- logger.error.apply(this, arguments)
- }
+ // function error(msg) {
+ // if (logger === undefined) {
+ // console.log('Error ', arguments)
+ // }
+ // else
+ // logger.error.apply(this, arguments)
+ // }
function warn(msg) {
if (logger === undefined) {
@@ -251,7 +251,7 @@ module.exports = function (container) {
return {
init: init,
- error: error,
+ // error: error,
warn: warn,
silly: silly,
debug: debug,
diff --git a/src/lib/logger/winston-helper.js b/src/lib/logger/winston-helper.js
index bf4a27cc..56dc3947 100755
--- a/src/lib/logger/winston-helper.js
+++ b/src/lib/logger/winston-helper.js
@@ -19,7 +19,7 @@
// dateFormat = require('dateformat'),
// util = require('util')
-module.exports = function(container) {
+module.exports = function (container) {
/*istanbul ignore next */
if (container.logModuleLoading)
console.log('Loading: winston-helper.js')
@@ -31,129 +31,145 @@ module.exports = function(container) {
var logger, packetLogger
- var init = function(){
+ var init = function () {
- logger = new (winston.Logger)({
- transports: [
- new (winston.transports.Console)({
+ if (container.settings.isReady()) {
+ console.log('Winstion initializing with customized settings.')
+
+ logger = new (winston.Logger)({
+ transports: [
+ new (winston.transports.Console)({
+ timestamp: function () {
+ return dateFormat(Date.now(), "HH:MM:ss.l");
+ },
+ formatter: function (options) {
+ // Return string will be passed to logger.
+ return options.timestamp() + ' ' + winston.config.colorize(options.level, options.level.toUpperCase()) + ' ' + (undefined !== options.message ? options.message : '') +
+ (options.meta && Object.keys(options.meta).length ? '\n\t' + JSON.stringify(options.meta) : '');
+ },
+ colorize: true,
+ level: container.settings.get('logLevel') || 'info',
+ stderrLevels: [],
+ handleExceptions: true,
+ humanReadableUnhandledException: true
+ })
+ ]
+ });
+
+ var fileLogEnable = 0
+ if (container.settings.has('fileLog.enable')) {
+ fileLogEnable = container.settings.get('fileLog.enable')
+ }
+ if (fileLogEnable) {
+ var _level = container.settings.get('fileLog.fileLogLevel')
+ var file = path.join(process.cwd(), container.settings.get('fileLog.fileName'))
+
+ var options = {
timestamp: function () {
return dateFormat(Date.now(), "HH:MM:ss.l");
},
+ level: _level,
formatter: function (options) {
// Return string will be passed to logger.
- return options.timestamp() + ' ' + winston.config.colorize(options.level, options.level.toUpperCase()) + ' ' + (undefined !== options.message ? options.message : '') +
+ return options.timestamp() + ' ' + options.level.toUpperCase() + ' ' + (undefined !== options.message ? options.message : '') +
(options.meta && Object.keys(options.meta).length ? '\n\t' + JSON.stringify(options.meta) : '');
},
- colorize: true,
- level: container.settings.get('logLevel') || 'info',
- stderrLevels: [],
- handleExceptions: true,
- humanReadableUnhandledException: true
- })
- ]
- });
- var fileLogEnable = 0
- if (container.settings.has('fileLog.enable')){
- fileLogEnable = container.settings.get('fileLog.enable')
- }
- if (fileLogEnable) {
- var _level = container.settings.get('fileLog.fileLogLevel')
- var file = path.join(process.cwd(), container.settings.get('fileLog.fileName'))
-
- var options = {
- timestamp: function () {
- return dateFormat(Date.now(), "HH:MM:ss.l");
- },
- level: _level,
- formatter: function (options) {
- // Return string will be passed to logger.
- return options.timestamp() + ' ' + options.level.toUpperCase() + ' ' + (undefined !== options.message ? options.message : '') +
- (options.meta && Object.keys(options.meta).length ? '\n\t' + JSON.stringify(options.meta) : '');
- },
- filename: file,
- colorize: false,
- json: false
+ filename: file,
+ colorize: false,
+ json: false
+ }
+ logger.add(winston.transports.File, options)
+
}
- logger.add(winston.transports.File, options)
- }
+
+ if (container.settings.get('capturePackets')) {
+ packetLogger = new (winston.Logger)({
+ transports: [
+ new (winston.transports.File)({
+ formatter: function (options) {
+ // Return string will be passed to logger.
+ return JSON.stringify(options.message);
+ },
+ colorize: false,
+ level: 'info',
+ handleExceptions: true,
+ humanReadableUnhandledException: false,
+ json: true,
+ filename: path.join(process.cwd(), 'replay/packetCapture.json')
+ })
+ ]
+ });
+ }
- if (container.settings.get('capturePackets'))
- {
- packetLogger = new (winston.Logger)({
+ }
+ else {
+ console.log('Winstion initializing with default settings.')
+ // initialize winston with defaults
+ logger = new (winston.Logger)({
transports: [
- new (winston.transports.File)({
+ new (winston.transports.Console)({
+ timestamp: function () {
+ return dateFormat(Date.now(), "HH:MM:ss.l");
+ },
formatter: function (options) {
// Return string will be passed to logger.
- return JSON.stringify(options.message);
+ return options.timestamp() + ' ' + winston.config.colorize(options.level, options.level.toUpperCase()) + ' ' + (undefined !== options.message ? options.message : '') +
+ (options.meta && Object.keys(options.meta).length ? '\n\t' + JSON.stringify(options.meta) : '');
},
- colorize: false,
+ colorize: true,
level: 'info',
+ stderrLevels: [],
handleExceptions: true,
- humanReadableUnhandledException: false,
- json: true,
- filename: path.join(process.cwd(), 'replay/packetCapture.json')
+ humanReadableUnhandledException: true
})
]
});
}
-
-
}
- function error(msg, ...args){
- // console.log('error msg: ', msg)
- // console.log('error args... ', args)
+ function error(msg){
+ if (logger===undefined){
+ init()
+ }
+ logger.error.apply(this, arguments)
+ }
+
+ function warn(msg){
if (logger===undefined){
- console.log('Error ', args)
- }
- else
- // is this right?
- logger.error.apply(this, args)
- }
-
- function warn(msg){
- if (logger===undefined){
- console.log('Warn ',arguments)
+ init()
}
- else
- logger.warn.apply(this, arguments)
- }
- function silly(msg){
+ logger.warn.apply(this, arguments)
+ }
+ function silly(msg){
if (logger===undefined){
init()
-
- logger.silly.apply(this, arguments)
}
- else
- logger.silly.apply(this, arguments)
- }
- function debug(msg){
+ logger.silly.apply(this, arguments)
+ }
+ function debug(msg){
if (logger===undefined){
- console.log('Debug ',arguments)
+ init()
}
- else
- logger.debug.apply(this, arguments)
- }
- function verbose(msg){
+ logger.debug.apply(this, arguments)
+ }
+ function verbose(msg){
if (logger===undefined){
- console.log('Verbose ',arguments)
+ init()
}
- else
- logger.verbose.apply(this, arguments)
- }
- function info(msg){
+ logger.verbose.apply(this, arguments)
+ }
+ function info(msg){
if (logger===undefined){
- console.log('Info ',arguments)
+ init()
}
- else
- logger.info.apply(this, arguments)
- }
+ logger.info.apply(this, arguments)
+ }
- function changeLevel(transport, lvl){
+ function changeLevel(transport, lvl) {
//when testing, we may call this first
- if (logger===undefined) {
+ if (logger === undefined) {
//init() //calling init here may lead to retrieving settings which we don't have yet... so print a message and move on
console.log('Error trying to call changeLevel when winston is not yet initialized')
@@ -162,12 +178,12 @@ module.exports = function(container) {
logger.transports[transport].level = lvl;
}
}
- function add(transport, options){
+ function add(transport, options) {
logger.add(transport, options)
}
- function packet(msg){
- packetLogger.info.apply(this, arguments)
+ function packet(msg) {
+ packetLogger.info.apply(this, arguments)
}
/*istanbul ignore next */
@@ -175,13 +191,13 @@ module.exports = function(container) {
logger.info('Loaded: winston-helper.js')
return {
- init:init,
+ init: init,
error: error,
warn: warn,
silly: silly,
debug: debug,
verbose: verbose,
- info: info,
+ info: info,
changeLevel: changeLevel,
add: add,
packet: packet
diff --git a/src/www/bootstrap/configClient.json b/src/www/bootstrap/configClient.json
index 5977afcf..51d35662 100755
--- a/src/www/bootstrap/configClient.json
+++ b/src/www/bootstrap/configClient.json
@@ -28,7 +28,7 @@
"state": "visible"
},
"intellichem": {
- "state": "visible"
+ "state": "hidden"
},
"release": {
"state": "visible"
diff --git a/src/www/bootstrap/index.html b/src/www/bootstrap/index.html
index eb069a39..fa4ba945 100755
--- a/src/www/bootstrap/index.html
+++ b/src/www/bootstrap/index.html
@@ -14,7 +14,7 @@
-
+
@@ -73,34 +73,35 @@
5.2.0 release notes | +5.3.0 release notes | ||
---|---|---|---|
Node 6+ | +Intellibrite | - This app no longer supports Node 4. + #106 fixed. API updates are now reflected in the /circuit object. | |
Update of modules. | +Browser caching | - Make sure to run `npm i` or `npm upgrade` to get the latest. + Much thanks to @arrmo for implementing browser side caching of web pages. Big speed improvements on loading the HTML pages. | |
Decoupled serial port and processing of packets. | +Server side session management | - Should help recovery upon packet errors. + Better management of sessions on the server. | |
Bug Fixes | +NPM I | - #95, #99, #100 + Re-run 'npm i' to update dependencies. + |