Added buttons for controlling pool equipment
This can be used with a touch screen, for example. I've also stubbed in functionality for controlling lights, heaters, and heat setpoints, but no actual UI exists for anything other than turning circuits on and off for now. That stuff is coming soon.
This commit is contained in:
@ -4,6 +4,10 @@ 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).
|
||||
|
||||
## [Unreleased]
|
||||
### Added
|
||||
- Ability to show buttons for controlling pool equipment (with a touch screen, for example).
|
||||
|
||||
## [1.0.3] - 2018-04-27
|
||||
### Changed
|
||||
- Packaged a newer `node-screenlogic` dependency to fix server broadcast in certain environments.
|
||||
|
@ -1,4 +1,5 @@
|
||||
poolData = {};
|
||||
var moduleObj;
|
||||
|
||||
Module.register("MMM-ScreenLogic",{
|
||||
defaults: {
|
||||
@ -9,6 +10,8 @@ Module.register("MMM-ScreenLogic",{
|
||||
showSaltLevel: true,
|
||||
showSaturation: true,
|
||||
showFreezeMode: true,
|
||||
showControls: false,
|
||||
controls: [],
|
||||
colored: true,
|
||||
coldTemp: 84,
|
||||
hotTemp: 90,
|
||||
@ -18,6 +21,13 @@ Module.register("MMM-ScreenLogic",{
|
||||
},
|
||||
|
||||
start: function() {
|
||||
// this isn't a great solution...is there a better one? needed to do stuff with buttons
|
||||
moduleObj = this;
|
||||
if (this.config.showControls && (!this.config.controls || this.config.controls.length == 0)) {
|
||||
Log.warn('Controls are enabled, but no controls are configured. See README for info on setting up controls.');
|
||||
this.config.showControls = false;
|
||||
}
|
||||
|
||||
this.sendSocketNotification('SCREENLOGIC_CONFIG', this.config);
|
||||
this.sendSocketNotification('SCREENLOGIC_UPDATE');
|
||||
},
|
||||
@ -98,6 +108,39 @@ Module.register("MMM-ScreenLogic",{
|
||||
class: this.config.contentClass
|
||||
});
|
||||
}
|
||||
if (this.config.showControls) {
|
||||
for (var control in this.config.controls) {
|
||||
var controlObj = this.config.controls[control];
|
||||
|
||||
var name = controlObj.name;
|
||||
for (var circuit in poolData.controllerConfig.bodyArray) {
|
||||
if (poolData.controllerConfig.bodyArray[circuit].circuitId == controlObj.id) {
|
||||
if (!name) {
|
||||
name = poolData.controllerConfig.bodyArray[circuit].name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var on = false;
|
||||
for (var circuit in poolData.status.circuitArray) {
|
||||
if (poolData.status.circuitArray[circuit].id == controlObj.id) {
|
||||
on = poolData.status.circuitArray[circuit].state !== 0;
|
||||
}
|
||||
}
|
||||
|
||||
var cls = '';
|
||||
if (this.config.colored) {
|
||||
cls = on ? 'control-on' : 'control-off';
|
||||
}
|
||||
|
||||
contents.push({
|
||||
data: '<button id="sl-control-' + controlObj.id + '" class="control ' + cls + '" onclick="setCircuit(this)" data-circuit="' +
|
||||
controlObj.id + '" data-state="' + (on ? '1' : '0') + '"><div class="content">' +
|
||||
name + '</div></button>',
|
||||
class: this.config.contentClass
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var headerRow = null;
|
||||
var contentRow = null;
|
||||
@ -116,15 +159,17 @@ Module.register("MMM-ScreenLogic",{
|
||||
for (var item in contents) {
|
||||
cols++;
|
||||
if (cols % this.config.columns === 0) {
|
||||
var headerRow = document.createElement('tr');
|
||||
var contentRow = document.createElement('tr');
|
||||
headerRow = document.createElement('tr');
|
||||
contentRow = document.createElement('tr');
|
||||
table.appendChild(headerRow);
|
||||
table.appendChild(contentRow);
|
||||
}
|
||||
|
||||
var headerCell = document.createElement('th');
|
||||
headerCell.innerHTML = contents[item].header;
|
||||
headerRow.appendChild(headerCell);
|
||||
if (contents[item].header) {
|
||||
var headerCell = document.createElement('th');
|
||||
headerCell.innerHTML = contents[item].header;
|
||||
headerRow.appendChild(headerCell);
|
||||
}
|
||||
|
||||
var contentCell = document.createElement('td');
|
||||
contentCell.innerHTML = contents[item].data;
|
||||
@ -140,8 +185,15 @@ Module.register("MMM-ScreenLogic",{
|
||||
if (notification === 'SCREENLOGIC_RESULT') {
|
||||
poolData = payload;
|
||||
this.updateDom();
|
||||
} else if (notification === 'SCREENLOGIC_CIRCUIT_DONE') {
|
||||
var obj = document.getElementById('sl-control-' + payload.id);
|
||||
if (this.config.colored) {
|
||||
var on = payload.state !== 0;
|
||||
obj.classList.add(on ? 'control-on' : 'control-off');
|
||||
}
|
||||
obj.dataset.state = payload.state;
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const SPA_CIRCUIT_ID = 500;
|
||||
@ -172,3 +224,10 @@ function isSpaActive(status) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function setCircuit(e) {
|
||||
var circuitId = parseInt(e.dataset.circuit);
|
||||
var on = e.dataset.state !== '0';
|
||||
moduleObj.sendSocketNotification('SCREENLOGIC_CIRCUIT', {id: circuitId, state: on ? 0 : 1});
|
||||
e.classList.remove('control-on', 'control-off');
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ A <a href="https://github.com/MichMich/MagicMirror">MagicMirror²</a> module use
|
||||
|---|---|---|---|
|
||||
|`serverAddress`|String|The IPv4 address of a ScreenLogic unit to connect to. If not set, the system will search for a unit to connect to. If set, `serverPort` must also be set.| |
|
||||
|`serverPort`|Integer|The port of a ScreenLogic unit to connect to (usually 80). If not set, the system will search for a unit to connect to. If set, `serverAddress` must also be set.| |
|
||||
|`showControls`|Boolean|Whether you'd like to show buttons for controlling pool equipment. Must also setup the `controls` array.|`false`|
|
||||
|`showPoolTemp`|Boolean|Whether you'd like to show pool temperature or not.|`true`|
|
||||
|`showSpaTemp`|Boolean|Whether you'd like to show spa temperature or not.|`true`|
|
||||
|`showPH`|Boolean|Whether you'd like to show pH level or not.|`true`|
|
||||
@ -21,6 +22,7 @@ A <a href="https://github.com/MichMich/MagicMirror">MagicMirror²</a> module use
|
||||
|`showFreezeMode`|Boolean|Whether you'd like to show a banner when the pool is in freeze mode or not. [added in v1.0.1]|`true`|
|
||||
|`colored`|Boolean|Whether you'd like colored output or not.|`true`|
|
||||
|`coldTemp`|Integer|Show the temperature colored blue if it's at or below this level for pool/spa (requires option `colored`). This is in whatever scale your system is set to (Fahrenheit/Celsius).|`84`|
|
||||
|`controls`|Array|List of controls to show buttons for. Must also set `showControls` to `true`.<br><br>Each entry in this list is an object with an `id` property and optionally a `name` override. If no `name` is specified, the name of the equipment in the ScreenLogic system will be used.|`[]`|
|
||||
|`hotTemp`|Integer|Show the temperature colored red if it's at or above this level for pool/spa (requires option `colored`). This is in whatever scale your system is set to (Fahrenheit/Celsius).|`90`|
|
||||
|`columns`|Integer|How many columns to use to display the data before starting a new row.|`3`|
|
||||
|`contentClass`|String|The CSS class used to display content values (beneath the header).|`"light"`|
|
||||
@ -35,7 +37,12 @@ Here is an example of an entry in config.js
|
||||
config: {
|
||||
showSpaTemp: false,
|
||||
columns: 2,
|
||||
contentClass: 'thin'
|
||||
contentClass: 'thin',
|
||||
showControls: true,
|
||||
controls: [
|
||||
{id: 500},
|
||||
{id: 505, name: 'Pool'}
|
||||
]
|
||||
}
|
||||
},
|
||||
```
|
||||
|
@ -12,6 +12,13 @@ module.exports = NodeHelper.create({
|
||||
});
|
||||
},
|
||||
|
||||
setCircuit: function(circuitState) {
|
||||
var self = this;
|
||||
setCircuitState(circuitState, function(done) {
|
||||
self.sendSocketNotification('SCREENLOGIC_CIRCUIT_DONE', circuitState);
|
||||
});
|
||||
},
|
||||
|
||||
setTimer: function(updateInterval) {
|
||||
var update = true;
|
||||
update = typeof this.updateInterval === 'undefined' || this.updateInterval != updateInterval;
|
||||
@ -37,16 +44,33 @@ module.exports = NodeHelper.create({
|
||||
if (notification === 'SCREENLOGIC_UPDATE') {
|
||||
this.doUpdate();
|
||||
}
|
||||
if (notification === 'SCREENLOGIC_CIRCUIT') {
|
||||
this.setCircuit(payload);
|
||||
}
|
||||
if (notification === 'SCREENLOGIC_HEATPOINT') {
|
||||
this.setHeatpoint(payload);
|
||||
}
|
||||
if (notification === 'SCREENLOGIC_HEATSTATE') {
|
||||
this.setHeatstate(payload);
|
||||
}
|
||||
if (notification === 'SCREENLOGIC_LIGHTCMD') {
|
||||
this.setLightcmd(payload);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const ScreenLogic = require('node-screenlogic');
|
||||
var foundUnit;
|
||||
|
||||
function getPoolData(config, cb) {
|
||||
if (typeof config === 'undefined' || !config.serverAddress || !config.serverPort) {
|
||||
findServer(cb);
|
||||
if (!foundUnit && typeof config !== 'undefined' && config.serverAddress && config.serverPort) {
|
||||
foundUnit = new ScreenLogic.UnitConnection(config.serverPort, config.serverAddress);
|
||||
}
|
||||
|
||||
if (foundUnit) {
|
||||
populateSystemData(cb);
|
||||
} else {
|
||||
populateSystemData(new ScreenLogic.UnitConnection(config.serverPort, config.serverAddress), cb);
|
||||
findServer(cb);
|
||||
}
|
||||
}
|
||||
|
||||
@ -54,26 +78,50 @@ function findServer(cb) {
|
||||
var finder = new ScreenLogic.FindUnits();
|
||||
finder.on('serverFound', function(server) {
|
||||
finder.close();
|
||||
populateSystemData(new ScreenLogic.UnitConnection(server), cb);
|
||||
|
||||
foundUnit = new ScreenLogic.UnitConnection(server);
|
||||
populateSystemData(cb);
|
||||
});
|
||||
|
||||
finder.search();
|
||||
}
|
||||
|
||||
function populateSystemData(unit, cb) {
|
||||
function populateSystemData(cb) {
|
||||
var poolData = {};
|
||||
|
||||
unit.on('loggedIn', function() {
|
||||
unit.getControllerConfig();
|
||||
}).on('controllerConfig', function(config) {
|
||||
if (!foundUnit) {
|
||||
cb(poolData);
|
||||
return;
|
||||
}
|
||||
|
||||
foundUnit.once('loggedIn', function() {
|
||||
foundUnit.getControllerConfig();
|
||||
}).once('controllerConfig', function(config) {
|
||||
poolData.controllerConfig = config;
|
||||
poolData.degStr = config.degC ? 'C' : 'F';
|
||||
unit.getPoolStatus();
|
||||
}).on('poolStatus', function(status) {
|
||||
foundUnit.getPoolStatus();
|
||||
}).once('poolStatus', function(status) {
|
||||
poolData.status = status;
|
||||
|
||||
unit.close();
|
||||
foundUnit.close();
|
||||
cb(poolData);
|
||||
});
|
||||
|
||||
unit.connect();
|
||||
foundUnit.connect();
|
||||
}
|
||||
|
||||
function setCircuitState(circuitState, cb) {
|
||||
if (!foundUnit) {
|
||||
cb();
|
||||
return;
|
||||
}
|
||||
|
||||
foundUnit.once('loggedIn', function() {
|
||||
foundUnit.setCircuitState(0, circuitState.id, circuitState.state);
|
||||
}).once('circuitStateChanged', function() {
|
||||
foundUnit.close();
|
||||
cb(true);
|
||||
});
|
||||
|
||||
foundUnit.connect();
|
||||
}
|
||||
|
@ -5,3 +5,52 @@
|
||||
.MMM-ScreenLogic table.colored .hot-temp {
|
||||
color: #FF8E99;
|
||||
}
|
||||
|
||||
.MMM-ScreenLogic td {
|
||||
width: 33%;
|
||||
}
|
||||
|
||||
.MMM-ScreenLogic button.control {
|
||||
background: #000;
|
||||
border: 1px solid #6c757d;
|
||||
font-size: .9rem;
|
||||
color: #fff;
|
||||
display: block;
|
||||
text-align: center;
|
||||
line-height: 1.5;
|
||||
transition: color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
width: 80%;
|
||||
height: 5rem;
|
||||
margin: auto;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.MMM-ScreenLogic button.control:after {
|
||||
padding-bottom: 100%;
|
||||
content: "";
|
||||
display: block;
|
||||
}
|
||||
|
||||
.MMM-ScreenLogic button.control .content {
|
||||
position: absolute;
|
||||
width: 90%;
|
||||
height: 90%;
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
padding: 5%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.control-on {
|
||||
background: #28a745 !important;
|
||||
border-color: #28a745 !important;
|
||||
}
|
||||
|
||||
.control-off {
|
||||
background: #6c757d !important;
|
||||
border-color: #6c757d !important;
|
||||
}
|
||||
|
Reference in New Issue
Block a user