homebridge-smartsystem
Version:
SmartServer (Proxy Websockets to TCP sockets, Smappee MQTT, Duotecno IP Nodes, Homekit interface)
590 lines • 24.8 kB
JavaScript
;
// Johan Coppieters.
// v1 - server version, Apr 2019
// v2 - app version, Jan 2020
// v3 - smart server version, Mar 2020
// v3.1 - added scenes from app version, May 2020
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.makeInt = exports.now = exports.datetime = exports.time = exports.date = exports.watt = exports.hex = exports.two = exports.char = exports.ascii = exports.wait = exports.Sanitizers = exports.actionValueStr = exports.actionValue = exports.kEmptyBinding = exports.kEmptyLink = exports.LinkType = exports.kEmptySwitch = exports.SwitchType = exports.kEmptyRule = exports.kEmptyAction = exports.RuleType = exports.Boundaries = exports.kEmptyCommRecord = exports.WriteError = exports.kEmptySettings = exports.kEmptyNetworkConfig = exports.kEmptyGroup = exports.kEmptyScene = exports.kEmptyUnitScene = exports.kEmptyUnit = exports.UnitExtendedType = exports.UnitType = exports.UnitMotorCmd = exports.UnitState = exports.NodeType = void 0;
const proxy_1 = require("../server/proxy");
// Node types
var NodeType;
(function (NodeType) {
NodeType[NodeType["kNoNode"] = 0] = "kNoNode";
NodeType[NodeType["kStandardNode"] = 1] = "kStandardNode";
NodeType[NodeType["kGatewayNode"] = 4] = "kGatewayNode";
NodeType[NodeType["kModemNode"] = 8] = "kModemNode";
NodeType[NodeType["kGUINode"] = 32] = "kGUINode";
})(NodeType = exports.NodeType || (exports.NodeType = {}));
;
// States
var UnitState;
(function (UnitState) {
UnitState[UnitState["kOpening"] = 4] = "kOpening";
UnitState[UnitState["kClosing"] = 3] = "kClosing";
UnitState[UnitState["kOpen"] = 2] = "kOpen";
UnitState[UnitState["kClosed"] = 1] = "kClosed";
UnitState[UnitState["kStopped"] = 0] = "kStopped";
})(UnitState = exports.UnitState || (exports.UnitState = {}));
;
var UnitMotorCmd;
(function (UnitMotorCmd) {
UnitMotorCmd[UnitMotorCmd["kClose"] = 5] = "kClose";
UnitMotorCmd[UnitMotorCmd["kOpen"] = 4] = "kOpen";
UnitMotorCmd[UnitMotorCmd["kStop"] = 3] = "kStop";
})(UnitMotorCmd = exports.UnitMotorCmd || (exports.UnitMotorCmd = {}));
;
var UnitType;
(function (UnitType) {
UnitType[UnitType["kNoType"] = 0] = "kNoType";
UnitType[UnitType["kDimmer"] = 1] = "kDimmer";
UnitType[UnitType["kSwitch"] = 2] = "kSwitch";
UnitType[UnitType["kInput"] = 3] = "kInput";
UnitType[UnitType["kTemperature"] = 4] = "kTemperature";
UnitType[UnitType["kExtendedAudio"] = 5] = "kExtendedAudio";
UnitType[UnitType["kMood"] = 7] = "kMood";
UnitType[UnitType["kSwitchingMotor"] = 8] = "kSwitchingMotor";
UnitType[UnitType["kAudio"] = 10] = "kAudio";
UnitType[UnitType["kAV"] = 11] = "kAV";
UnitType[UnitType["kIRTX"] = 12] = "kIRTX";
UnitType[UnitType["kVideo"] = 14] = "kVideo";
})(UnitType = exports.UnitType || (exports.UnitType = {}));
;
var UnitExtendedType;
(function (UnitExtendedType) {
UnitExtendedType[UnitExtendedType["kNoType"] = 0] = "kNoType";
UnitExtendedType[UnitExtendedType["kDimmer"] = 1] = "kDimmer";
UnitExtendedType[UnitExtendedType["kSwitch"] = 2] = "kSwitch";
UnitExtendedType[UnitExtendedType["kInput"] = 3] = "kInput";
UnitExtendedType[UnitExtendedType["kTemperature"] = 4] = "kTemperature";
UnitExtendedType[UnitExtendedType["kExtendedAudio"] = 5] = "kExtendedAudio";
UnitExtendedType[UnitExtendedType["kMood"] = 7] = "kMood";
UnitExtendedType[UnitExtendedType["kSwitchingMotor"] = 8] = "kSwitchingMotor";
UnitExtendedType[UnitExtendedType["kAudio"] = 10] = "kAudio";
UnitExtendedType[UnitExtendedType["kAV"] = 11] = "kAV";
UnitExtendedType[UnitExtendedType["kIRTX"] = 12] = "kIRTX";
UnitExtendedType[UnitExtendedType["kVideo"] = 14] = "kVideo";
UnitExtendedType[UnitExtendedType["kPower"] = 24] = "kPower";
UnitExtendedType[UnitExtendedType["kLightbulb"] = 101] = "kLightbulb";
UnitExtendedType[UnitExtendedType["kCondition"] = 102] = "kCondition";
UnitExtendedType[UnitExtendedType["kGarageDoor"] = 201] = "kGarageDoor";
UnitExtendedType[UnitExtendedType["kDoor"] = 202] = "kDoor";
UnitExtendedType[UnitExtendedType["kLock"] = 203] = "kLock";
UnitExtendedType[UnitExtendedType["kUnlocker"] = 204] = "kUnlocker";
})(UnitExtendedType = exports.UnitExtendedType /* extends UnitType */ || (exports.UnitExtendedType /* extends UnitType */ = {}));
;
;
;
;
;
exports.kEmptyUnit = { masterAddress: "0.0.0.0", masterPort: 5001,
name: "unit", logicalAddress: 0, logicalNodeAddress: 0 };
;
;
;
exports.kEmptyUnitScene = Object.assign(Object.assign({}, exports.kEmptyUnit), { value: true });
;
exports.kEmptyScene = { name: 'Scene', trigger: Object.assign({}, exports.kEmptyUnitScene), order: 0, units: [] };
;
exports.kEmptyGroup = { name: "Home", id: 0, order: 0, visible: true };
;
exports.kEmptyNetworkConfig = { ip1: "", ip2: "", gateway1: "", gateway2: "", nameservers: "" };
;
exports.kEmptySettings = { network: exports.kEmptyNetworkConfig };
;
;
;
var WriteError;
(function (WriteError) {
WriteError[WriteError["writeFatal"] = -1] = "writeFatal";
WriteError[WriteError["writeError"] = 0] = "writeError";
WriteError[WriteError["writeOK"] = 1] = "writeOK";
})(WriteError = exports.WriteError || (exports.WriteError = {}));
exports.kEmptyCommRecord = { status: false, cmd: -1, message: [-1, 0, 0], rest: "" };
//////////////
// SmartApp //
//////////////
var Boundaries;
(function (Boundaries) {
Boundaries[Boundaries["kLow"] = 0] = "kLow";
Boundaries[Boundaries["kMid"] = 1] = "kMid";
Boundaries[Boundaries["kHigh"] = 2] = "kHigh";
})(Boundaries = exports.Boundaries || (exports.Boundaries = {}));
;
var RuleType;
(function (RuleType) {
RuleType["kPower"] = "power";
RuleType["kCurrent"] = "current";
RuleType["kWater"] = "water";
})(RuleType = exports.RuleType || (exports.RuleType = {}));
;
exports.kEmptyAction = Object.assign(Object.assign({}, exports.kEmptyUnit), { value: false });
;
exports.kEmptyRule = {
type: "power", channel: "0", low: 30, high: 900,
actions: [Object.assign(Object.assign({}, exports.kEmptyUnit), { value: false }), Object.assign(Object.assign({}, exports.kEmptyUnit), { value: 50 }), Object.assign(Object.assign({}, exports.kEmptyUnit), { value: true })]
};
// Switches
var SwitchType;
(function (SwitchType) {
SwitchType["kNoType"] = "";
SwitchType["kSmappee"] = "smappee";
SwitchType["kRF"] = "RF";
SwitchType["kHTTPSwitch"] = "http";
SwitchType["kHTTPDimmer"] = "httpdim";
SwitchType["kHTTPUpDown"] = "httpupdown";
SwitchType["kOhSwitch"] = "oswitch";
SwitchType["kOhDimmer"] = "odimmer";
SwitchType["kOhUpDown"] = "oupdown";
SwitchType["kSomfy"] = "somfy";
})(SwitchType = exports.SwitchType || (exports.SwitchType = {}));
exports.kEmptySwitch = Object.assign(Object.assign({}, exports.kEmptyUnit), { plug: 0, type: SwitchType.kNoType, unitName: "", name: "", data: "", method: "GET", header: "", username: "", password: "", nomacro: "N", nostop: "N" });
// Links
var LinkType;
(function (LinkType) {
LinkType["kNoType"] = "";
LinkType["kAccessory"] = "accessory";
})(LinkType = exports.LinkType || (exports.LinkType = {}));
exports.kEmptyLink = Object.assign(Object.assign({}, exports.kEmptyUnit), { type: LinkType.kNoType, max: 100, min: 0, accName: "acc", accId: "", accService: [] });
exports.kEmptyBinding = {
channel: "0", masterAddress: "0.0.0.0", masterPort: 5001, register: 0
};
;
;
;
;
;
/////////////
// Smappee //
/////////////
function actionValue(val) {
if ((typeof val === "number") || (typeof val === "boolean"))
return val;
let x = parseInt(val);
if (isNaN(x))
return (val === "true") || (val === "TRUE") || (val === "True");
else
return x;
}
exports.actionValue = actionValue;
function actionValueStr(val) {
if (typeof val === "boolean")
return (val) ? "true" : "false";
else
return val.toString();
}
exports.actionValueStr = actionValueStr;
////////////////
// Sanitizers //
////////////////
exports.Sanitizers = {
accessory: function (config) {
if (!config)
config = {};
config.accessory = config.accessory || "DuotecnoAccessory";
config.name = config.name || "Duotecno-Coppieters";
// for sp4pro -> "device": "/dev/serial0", "baudrate": "9600"
return config;
},
platform: function (config) {
if (!config)
config = {};
config.manufacturer = config.manufacturer || "Duotecno-Coppieters";
config.platform = config.platform || "DuotecnoPlatform";
config.smappee = config.smappee || false;
config.p1 = config.p1 || false;
config.shelly = config.shelly || false;
config.smartapp = config.smartapp || null;
config.system = exports.Sanitizers.system(config.system);
config.proxy = exports.Sanitizers.proxy(config.proxy, config.system);
return config;
},
homebridge: function (config) {
if (!config)
config = {};
config.bridge = config.bridge || {};
config.bridge.name = config.bridge.name || "Duotecno Bridge";
config.bridge.username = config.bridge.username || "CC:22:3D:E3:A3:01";
config.bridge.port = config.bridge.port || 51827;
config.bridge.pin = config.bridge.pin || "577-03-001";
config.platforms = config.platforms || [{}];
for (let p in config.platforms)
if (config.platforms[p].platform == "DuotecnoPlatform")
config.platforms[p] = exports.Sanitizers.platform(config.platforms[p]);
config.accessories = []; //config.accessories || [<AccessoryConfig>{}];
//for (let a in config.accessories) Sanitizers.accessory(config.accessories[a]);
return config;
},
settings: function (config) {
if (!config)
config = {};
config.network = exports.Sanitizers.networkConfig(config.network);
return config;
},
networkConfig: function (config) {
if (!config)
config = {};
config.ip1 = config.ip1 || exports.kEmptyNetworkConfig.ip1;
config.ip2 = config.ip2 || exports.kEmptyNetworkConfig.ip2;
config.gateway1 = config.gateway1 || exports.kEmptyNetworkConfig.gateway1;
config.gateway2 = config.gateway2 || exports.kEmptyNetworkConfig.gateway2;
config.nameservers = config.nameservers || exports.kEmptyNetworkConfig.nameservers;
return config;
},
server: function (config) {
if (!config)
return { debug: true, port: 9999 };
config.port = config.port || 9999;
if (typeof config.port === "string")
config.port = parseInt(config.port);
if (typeof config.debug === "undefined")
config.debug = true;
return config;
},
smartapp: function (config) {
if (!config)
config = {};
config.port = config.port || 5002;
config.switches = config.switches || [];
config.switches = config.switches.map(sw => exports.Sanitizers.switchConfig(sw));
config.links = config.links || [];
config.links = config.links.map(sw => exports.Sanitizers.linkConfig(sw));
config.debug = config.debug || false;
config.apiHost = config.apiHost || "localhost";
config.apiPort = config.apiPort || 8581;
config.username = config.username || "admin";
config.password = config.password || "";
return config;
},
powerbase: function (config) {
if (!config)
config = {};
config.debug = config.debug || false;
config.rules = config.rules || [];
config.rules = config.rules.map(sw => exports.Sanitizers.ruleConfig(sw));
config.bindings = config.bindings || [];
config.bindings = config.bindings.map(b => exports.Sanitizers.bindingConfig(b));
config.address = config.address || "";
return config;
},
smappee: function (config) {
if (!config)
config = {};
const cfg = exports.Sanitizers.powerbase(config);
cfg.uid = config.uid || "--none--";
return cfg;
},
p1: function (config) {
if (!config)
config = {};
const cfg = exports.Sanitizers.powerbase(config);
return cfg;
},
shelly: function (config) {
if (!config)
config = {};
const cfg = exports.Sanitizers.powerbase(config);
cfg.addresses = (config === null || config === void 0 ? void 0 : config.addresses) || "";
return cfg;
},
linkConfig: function (aLink) {
const link = exports.Sanitizers.unitDef(aLink);
link.accId = aLink.accId || "";
link.accName = aLink.accName || "";
link.accService = aLink.accService || [];
link.type = aLink.type || exports.kEmptyLink.type;
link.max = aLink.max || exports.kEmptyLink.max;
link.min = aLink.min || exports.kEmptyLink.min;
return link;
},
switchConfig: function (aSwitch) {
const sw = exports.Sanitizers.unitDef(aSwitch);
sw.nomacro = aSwitch.nomacro || "N";
sw.nostop = aSwitch.nostop || "N";
sw.name = aSwitch.name || "--";
sw.unitName = aSwitch.unitName || "";
sw.value = aSwitch.value || 0;
sw.data = aSwitch.data || "";
sw.header = aSwitch.header || "";
sw.method = aSwitch.method || "GET";
sw.type = aSwitch.type || SwitchType.kNoType;
// don't destroy 0 plug
if (typeof aSwitch.plug === "string")
sw.plug = aSwitch.plug || "";
return sw;
},
makeSwitchConfig: function (aSwitch) {
return exports.Sanitizers.switchConfig({ name: aSwitch.name, unitName: aSwitch.unitName,
masterAddress: aSwitch.masterAddress, masterPort: aSwitch.masterPort,
nomacro: aSwitch.nomacro, nostop: aSwitch.nostop,
logicalAddress: aSwitch.logicalAddress, logicalNodeAddress: aSwitch.logicalNodeAddress,
type: aSwitch.type, plug: aSwitch.plug,
data: aSwitch.data, method: aSwitch.method, header: aSwitch.header });
},
makeLinkConfig: function (aLink) {
return exports.Sanitizers.linkConfig({ name: aLink.name, unitName: aLink.unitName,
masterAddress: aLink.masterAddress, masterPort: aLink.masterPort,
logicalAddress: aLink.logicalAddress, logicalNodeAddress: aLink.logicalNodeAddress,
accName: aLink.accName, accService: aLink.accService, accId: aLink.accId, type: aLink.type });
},
ruleConfig(rule) {
rule = Object.assign({}, rule);
rule.channel = rule.channel || "0";
rule.low = makeInt(rule.low);
rule.high = makeInt(rule.high);
if (typeof rule.actions === "undefined")
rule.actions = [];
while (rule.actions.length < 2)
rule.actions.push(Object.assign({}, exports.kEmptyAction));
rule.actions.forEach(action => {
action.value = actionValue(action.value);
action.logicalAddress = makeInt(action.logicalAddress);
action.logicalNodeAddress = makeInt(action.logicalNodeAddress);
if (typeof action.name != "string")
action.name = "";
});
return rule;
},
bindingConfig(binding) {
const b = Object.assign({}, exports.kEmptyBinding);
b.masterAddress = binding.masterAddress || '',
b.register = binding.register || 0,
b.masterPort = binding.masterPort || 5001,
b.channel = binding.channel || "0";
return b;
},
///////////
// Proxy //
///////////
proxy: function (config, system) {
var _a, _b;
const c = proxy_1.kEmptyProxy;
c.cloudServer = (config === null || config === void 0 ? void 0 : config.cloudServer) || proxy_1.kEmptyProxy.cloudServer;
c.cloudPort = (config === null || config === void 0 ? void 0 : config.cloudPort) || proxy_1.kEmptyProxy.cloudPort;
c.masterAddress = (config === null || config === void 0 ? void 0 : config.masterAddress) || ((_a = system === null || system === void 0 ? void 0 : system.cmasters[0]) === null || _a === void 0 ? void 0 : _a.address) || "";
c.masterPort = (config === null || config === void 0 ? void 0 : config.masterPort) || ((_b = system === null || system === void 0 ? void 0 : system.cmasters[0]) === null || _b === void 0 ? void 0 : _b.port) || 5001;
c.uniqueId = (config === null || config === void 0 ? void 0 : config.uniqueId) || proxy_1.kEmptyProxy.uniqueId;
return c;
},
//////////////
// Duotecno //
//////////////
masterConfig: function (config) {
config = (config) ? Object.assign({}, config) : {};
config.name = config.name || "IP Master";
config.address = config.address || "";
config.port = config.port || 0;
if (typeof config.port === "string")
config.port = parseInt(config.port);
config.password = config.password || "";
config.debug = config.debug || false;
if (typeof config.active === "undefined")
config.active = true;
config.active = !!config.active;
config.nodenames = config.nodenames || {};
return config;
},
system: function (config) {
if (!config)
config = {};
config.mood = config.mood || "sfeer";
config.debug = config.debug || false;
config.socketserver = config.socketserver || 'ws.duotecno.eu';
// correct old settings
if (config.socketserver == 'akiworks.be')
config.socketserver = 'ws.duotecno.eu';
config.socketport = config.socketport || 9999;
config.cmasters = config.cmasters || [];
config.cmasters = config.cmasters.map(m => exports.Sanitizers.masterConfig(m));
config.cunits = config.cunits || [];
config.cunits = config.cunits.map(u => exports.Sanitizers.unitConfig(u));
return config;
},
//////////
// Node //
nodeConfig: function (config) {
if (!config)
config = {};
config.active = config.active || "N";
config.masterAddress = config.masterAddress || "";
config.masterPort = config.masterPort || 5001;
config.logicalAddress = config.logicalAddress || 0;
return config;
},
//////////
// Unit //
unitDef: function (info) {
return {
logicalNodeAddress: info.logicalNodeAddress || 0,
logicalAddress: info.logicalAddress || 0,
masterAddress: info.masterAddress || '',
masterPort: info.masterPort || 5001,
name: info.name || ('unit ' + info.logicalNodeAddress + ":" + info.logicalAddress),
displayName: info.displayName || info.name || ('unit ' + info.logicalNodeAddress + ":" + info.logicalAddress),
extendedType: info.extendedType || UnitExtendedType.kNoType
};
},
unitConfig: function (config) {
if (!config) {
config = {};
}
const cfg = exports.Sanitizers.unitDef(config);
cfg.active = config.active || 'N';
cfg.used = config.used || config.active;
if (typeof config.group === 'string') {
config.group = parseInt(config.group);
}
cfg.group = config.group || 0;
return cfg;
},
unitScene: function (config) {
// change + create new clean record for writing to config files
if (!config) {
config = {};
}
const cfg = exports.Sanitizers.unitDef(config);
if (typeof config.value === "undefined")
cfg.value = 0;
if (typeof config.value === "string")
cfg.value = parseInt(config.value);
cfg.name = config.name || "New scene";
return { logicalNodeAddress: cfg.logicalNodeAddress,
logicalAddress: cfg.logicalAddress,
masterAddress: cfg.masterAddress,
masterPort: cfg.masterPort,
value: cfg.value,
name: cfg.name };
},
////////////
// Scenes //
sceneConfig: function (config) {
// don't change -> create new clean record for writing to config files
if (!config) {
return Object.assign({}, exports.kEmptyScene);
}
const newConfig = Object.assign({}, exports.kEmptyScene);
newConfig.name = config.name || exports.kEmptyScene.name;
if (typeof config.order === 'string') {
newConfig.order = parseInt(config.order);
}
newConfig.order = config.order || exports.kEmptyScene.order;
newConfig.trigger = exports.Sanitizers.unitScene(config.trigger);
config.units = config.units || exports.kEmptyScene.units;
newConfig.units = config.units.map(u => exports.Sanitizers.unitScene(u));
return newConfig;
},
scenes: function (config) {
if (!config) {
return [exports.Sanitizers.sceneConfig()];
}
config = config.map(s => exports.Sanitizers.sceneConfig(s));
return config;
},
///////////////////////////////////
// Data coming from the hardware //
nodeInfo: function (info, into) {
info.name = info.name || "";
info.index = info.index || -1;
info.logicalAddress = info.logicalAddress || 0;
info.physicalAddress = info.physicalAddress || 0;
info.type = info.type || NodeType.kNoNode;
info.flags = info.flags || 0;
info.nrUnits = info.nrUnits || 0;
if (into) {
Object.keys(info).forEach(prop => into[prop] = info[prop]);
}
return info;
},
unitInfo: function (info, into) {
info.name = info.name || "";
info.displayName = info.displayName || "";
info.index = info.index || -1;
info.logicalNodeAddress = info.logicalNodeAddress || 0;
info.logicalAddress = info.logicalAddress || 0;
info.type = info.type || UnitType.kNoType;
info.extendedType = info.extendedType || info.type;
info.flags = info.flags || 0;
if (into) {
Object.keys(info).forEach(prop => into[prop] = info[prop]);
}
return info;
}
};
//////////////////////
// Helper functions //
//////////////////////
function wait(sec) {
return __awaiter(this, void 0, void 0, function* () {
return new Promise(resolve => setTimeout(resolve, sec * 1000));
});
}
exports.wait = wait;
function ascii(char) {
return char.charCodeAt(0);
}
exports.ascii = ascii;
function char(ascii) {
return String.fromCharCode(ascii);
}
exports.char = char;
function two(n) {
return (+n < 10) ? ("0" + n) : n.toString();
}
exports.two = two;
function hex(n) {
n = Math.floor(n);
return "0x" + n.toString(16);
}
exports.hex = hex;
function watt(w) {
if (w < 1000)
return w + "W";
if (w < 1000000)
return Math.floor(w / 1000) + "." + (Math.round(w / 100) % 10) + "KW";
if (w < 1000000000)
return Math.floor(w / 1000000) + "." + (Math.round(w / 100000) % 10) + "MW";
return Math.floor(w / 1000000000) + "." + (Math.round(w / 100000000) % 10) + "GW";
}
exports.watt = watt;
function date(aDate) {
if (!aDate)
return "-";
return two(aDate.getDate()) + "-" + two(aDate.getMonth() + 1) + "-" + aDate.getFullYear();
}
exports.date = date;
function time(aDate) {
if (!aDate)
return "-";
return two(aDate.getHours()) + ":" + two(aDate.getMinutes()) + ":" + two(aDate.getSeconds());
}
exports.time = time;
function datetime(aDate) {
if (!aDate)
return "-";
return date(aDate) + " " + time(aDate);
}
exports.datetime = datetime;
function now() {
return datetime(new Date());
}
exports.now = now;
function makeInt(val) {
if (typeof val === "string") {
if ((val[0] === '0') && (val[1] === 'x'))
val = parseInt(val.substr(2), 16);
else
val = parseInt(val, 10);
}
return isNaN(val) ? 0 : val;
}
exports.makeInt = makeInt;
//# sourceMappingURL=types.js.map