homey-signal-validator
Advanced tools
Comparing version 1.0.0 to 2.0.0
var SignalValidator = require('..'); | ||
var definition = { | ||
sof: [], // Start of frame | ||
eof: [295], // End of frame | ||
words: [ | ||
[295, 885], // 0 | ||
[885, 295] // 1 | ||
], | ||
interval: 9565, // Time between repititions | ||
repetitions: 20, | ||
sensitivity: 0.7, | ||
minimalLength: 24, | ||
maximalLength: 24 | ||
} | ||
var definition = { | ||
sof: [ 1,1,1,1,1,1,1,1,1, | ||
0,0,1,0,1,0,1,0,1,0,1,0,1,1,0,0,1,1,0,0,1], // preamble = 3f5 | ||
words: [ | ||
[1, 0], // 0 | ||
[0, 1], // 1 | ||
], | ||
eof: [], | ||
manchesterUnit: 10, //us | ||
manchesterMaxUnits: 10, | ||
carrier: 433934000, | ||
repetitions: 10, | ||
sensitivity: 0.5, | ||
interval: 500, | ||
packing: true, | ||
rxTimeout: 200, | ||
cmds: { | ||
"Test":[0,1,0,1] | ||
}, | ||
modulation: { | ||
type: 'GFSK', | ||
baudRate: 100000, | ||
channelSpacing: 100000, | ||
channelDeviation: 50000, | ||
} | ||
} | ||
@@ -34,2 +47,2 @@ var opts = { | ||
console.error(e.stack); | ||
} | ||
} |
"use strict"; | ||
var util = require('util'); | ||
var extend = util._extend; | ||
/* static functions */ | ||
function _validate(validator, check, signal) { | ||
for (var propName in signal) { | ||
var property = signal[propName]; | ||
var validate = validator[propName]; | ||
if(typeof validate === 'function') { | ||
var res = validate(property, signal); | ||
check(res.msg, res.result); | ||
} | ||
} | ||
} | ||
function SignalValidator( signal, opts ) { | ||
function _valid_bounds(value, min, max) { | ||
var res = true; | ||
if(value instanceof Array) { | ||
value.forEach(function(val) { | ||
if(val < min || val > max) { | ||
res = false; | ||
} | ||
}); | ||
} else if(typeof value === 'number') { | ||
if(value < min || value > max) | ||
res = false; | ||
} | ||
this.signal = signal; | ||
this.opts = extend({ | ||
frequency: undefined // 433, 868, ir | ||
}, opts); | ||
return res; | ||
} | ||
function _valid_odd_signal(signal) { | ||
if(signal.hasOwnProperty('manchesterUnit')) return true; | ||
var total = 0; | ||
total += (signal.sof instanceof Array) ? signal.sof.length : 0; | ||
total += (signal.eof instanceof Array) ? signal.eof.length : 0; | ||
return total % 2 !== 0; | ||
} | ||
SignalValidator.prototype.valid = function(){ | ||
function _valid_pronto_string(pronto) { | ||
return typeof pronto === 'string' && (/^([0-9a-f]{4}\s?){4,}$/i).test(pronto); | ||
} | ||
return true; // TODO because reinier didn't fix this | ||
/* ---------------- */ | ||
var results = []; | ||
/* property validators */ | ||
var genBounds = { | ||
manchesterMaxUnits: { min: 1, max: 1000 }, | ||
sensitivity: { min: 0.0, max: 0.5 }, | ||
minimalLength: { min: 0, max: 1000 }, | ||
maximalLength: { min: 0, max: 1000 }, | ||
}; | ||
function check( message, result ){ | ||
if( result !== true ) results.push(message); | ||
function _validateGenericData(data, signal) { | ||
var res = { result: true, msg: "invalid_"+this }; | ||
if(!(data instanceof Array)) { | ||
res.result = false; | ||
return res; | ||
} | ||
if(data.some(function(word) { | ||
return (!signal.words || !signal.words[word]); | ||
})) res.result = false; | ||
return res; | ||
} | ||
// first, check if the signal is valid | ||
// START GENERIC TESTS | ||
check( 'invalid_interval_type' , typeof this.signal.interval == 'number' ); | ||
// END GENERIC TESTS | ||
var genericValidator = { | ||
words: function(words, signal) { | ||
var res = { result: true, msg: "invalid_words" }; | ||
if(!(words instanceof Array) || words.length <= 1) { | ||
res.result = false; | ||
return res; | ||
} | ||
// check if word has more then 1 interval | ||
words.forEach(function(word) { | ||
if(!(word instanceof Array) || word.length <= 1) { | ||
res.result = false; | ||
return res; | ||
} | ||
}); | ||
return res; | ||
}, | ||
agc: function(agc, signal) { | ||
var res = agc instanceof Array; | ||
return { result: res, msg: "invalid_agc" }; | ||
}, | ||
sof: function(sof, signal) { | ||
var res = sof instanceof Array; | ||
return { result: res, msg: "invalid_sof" }; | ||
}, | ||
toggleSof: function(toggleSof, signal) { | ||
var res = toggleSof instanceof Array; | ||
return { result: res, msg: "invalid_toggleSof" }; | ||
}, | ||
eof: function(eof, signal) { | ||
var res = eof instanceof Array; | ||
return { result: res, msg: "invalid_eof" }; | ||
}, | ||
manchesterUnit: function(manchesterUnit, signal) { | ||
var res = typeof manchesterUnit === "number"; | ||
return { result: res, msg: "invalid_manchesterUnit" }; | ||
}, | ||
manchesterMaxUnits: function(manchesterMaxUnits, signal) { | ||
var res = typeof manchesterMaxUnits === "number" && manchesterMaxUnits >= genBounds.manchesterMaxUnits.min; | ||
return { result: res, msg: "invalid_manchesterMaxUnits" }; | ||
}, | ||
sensitivity: function(sensitivity, signal) { | ||
var res = typeof sensitivity === "number" && _valid_bounds(sensitivity, genBounds.sensitivity.min, genBounds.sensitivity.max); | ||
return { result: res, msg: "invalid_sensitivity" }; | ||
}, | ||
interval: function(interval, signal) { | ||
var res = typeof interval === "number"; | ||
return { result: res, msg: 'invalid_signalinterval' }; | ||
}, | ||
minimalLength: function(minLength, signal) { | ||
var res = minLength > 0; | ||
return { result: res, msg: "invalid_minimalLength" }; | ||
}, | ||
maximalLength: function(maxLength, signal) { | ||
var res = maxLength > 0; | ||
return { result: res, msg: "invalid_maximalLength" }; | ||
}, | ||
packing: function(packing, signal) { | ||
var res = typeof packing === 'boolean' && signal.words.length == 2; | ||
return { result: res, msg: "invalid_packing" }; | ||
}, | ||
dutyCycle: function(dutyCycle, signal) { | ||
var res = typeof dutyCycle === 'number'; | ||
return { result: res, msg: "invalid_dutyCycle" }; | ||
}, | ||
txOnly: function(txOnly, signal) { | ||
var res = typeof txOnly === 'boolean'; | ||
return { result: res, msg: "invalid_txOnly" }; | ||
}, | ||
cmds: function(cmds, signal) { | ||
var res = { result: true, msg: "invalid_cmd" }; | ||
Object.keys(cmds).forEach(function(cmd) { | ||
if(!_validateGenericData(cmds[cmd], signal).result) res.result = false; | ||
}); | ||
return res; | ||
}, | ||
toggleIndexes: function(toggleIndexes, signal) { | ||
var res = toggleIndexes instanceof Array && !toggleIndexes.some(function(index) { return index >= signal.sof.length; }); | ||
return { result: res, msg: "invalid_toggleIndexes" }; | ||
}, | ||
toggleBits: function(toggleBits, signal) { | ||
var res = toggleBits instanceof Array; | ||
return { result: res, msg: "invalid_toggleBits" }; | ||
}, | ||
prefixData: _validateGenericData.bind("prefixData"), | ||
postfixData: _validateGenericData.bind("postfixData"), | ||
}; | ||
// second, check if the signal is valid for the specific frequency | ||
if( typeof this.opts.frequency == 'string' ) { | ||
check( 'invalid_frequency' , typeof this[ 'valid_' + this.opts.frequency ] == 'function' ); | ||
var rfBounds = { timeInterval: { min: 5, max: 32767 }, | ||
manchesterInterval: { min: 0, max: 1 }, | ||
rxTimeout: { min: 0, max: 255 }, | ||
repetitions: {min: 1, max: 255}, | ||
}; | ||
if( typeof this[ 'valid_' + this.opts.frequency ] == 'function' ) { | ||
this[ 'valid_' + this.opts.frequency ].call( this, function(){ | ||
return check.apply( this, arguments ); | ||
}.bind(this)); | ||
var rfValidator = { | ||
words: function(words, signal) { | ||
var res = { result: true, msg: "word_interval_out_of_bounds" }; | ||
var bounds = !signal.hasOwnProperty('manchesterUnit') ? rfBounds.timeInterval : rfBounds.manchesterInterval; | ||
words.forEach(function(word) { | ||
if(!_valid_bounds(word, bounds.min , bounds.max)) { | ||
res.result = false; | ||
} | ||
}); | ||
return res; | ||
}, | ||
agc: function(agc, signal) { | ||
var bounds = !signal.hasOwnProperty('manchesterUnit') ? rfBounds.timeInterval : rfBounds.manchesterInterval; | ||
var res = _valid_bounds(agc, bounds.min, bounds.max); | ||
return { result: res, msg: "agc_out_of_bounds" }; | ||
}, | ||
toggleSof: function(toggleSof, signal) { | ||
var bounds = !signal.hasOwnProperty('manchesterUnit') ? rfBounds.timeInterval : rfBounds.manchesterInterval; | ||
var res = _valid_bounds(toggleSof, bounds.min, bounds.max); | ||
return { result: res, msg: "toggleSof_out_of_bounds" }; | ||
}, | ||
sof: function(sof, signal) { | ||
var bounds = !signal.hasOwnProperty('manchesterUnit') ? rfBounds.timeInterval : rfBounds.manchesterInterval; | ||
var res = _valid_bounds(sof, bounds.min, bounds.max); | ||
return { result: res, msg: "sof_out_of_bounds" }; | ||
}, | ||
eof: function(eof, signal) { | ||
var bounds = !signal.hasOwnProperty('manchesterUnit') ? rfBounds.timeInterval : rfBounds.manchesterInterval; | ||
var res = _valid_bounds(eof, bounds.min , bounds.max); | ||
return { result: res, msg: "eof_out_of_bounds" }; | ||
}, | ||
repetitions: function(repetitions, signal) { | ||
var res = _valid_bounds(repetitions, rfBounds.repetitions.min, rfBounds.repetitions.max); | ||
return { result: res, msg: "repetitions_out_of_bounds" }; | ||
}, | ||
interval: function(interval, signal) { | ||
var res = _valid_bounds(interval, rfBounds.timeInterval.min, rfBounds.timeInterval.max); | ||
return { result: res, msg: "interval_out_of_bounds" }; | ||
}, | ||
rxTimeout: function(rxTimeout, signal) { | ||
var res = _valid_bounds(rxTimeout, rfBounds.rxTimeout.min, rfBounds.rxTimeout.max); | ||
return { result: res, msg: "rxTimeout_out_of_bounds" }; | ||
}, | ||
manchesterUnit: function(manchesterUnit, signal) { | ||
var res = _valid_bounds(manchesterUnit, rfBounds.timeInterval.min, rfBounds.timeInterval.max); | ||
return { result: res, msg: "manchesterUnit_out_of_bounds" }; | ||
}, | ||
}; | ||
var modulationBounds = { baudRate: { min: 1000, max: 200000 }, | ||
channelSpacing: { min: 58000, max: 812000 }, | ||
channelDeviation: { min: 5000, max: 50000 }, | ||
}; | ||
var modulationValidator = { | ||
modulation: function(modulation, signal) { | ||
// replace by default modulation props in homey-microcontroller? | ||
var mandatoryProps = ['type', 'baudRate', 'channelSpacing', 'channelDeviation']; | ||
var res = { result: true, msg: "invalid_modulation_properties"}; | ||
mandatoryProps.forEach(function(prop) { | ||
if(!modulation.hasOwnProperty(prop) ) { | ||
res.result = false; | ||
return res; | ||
} | ||
}); | ||
if(modulation.type !== 'ASK' && modulation.type !== 'FSK' && modulation.type !== 'GFSK') { | ||
res.result = false; | ||
return res; | ||
} | ||
if(!_valid_bounds(modulation.baudRate, modulationBounds.baudRate.min, modulationBounds.baudRate.max)) { | ||
res.result = false; | ||
return res; | ||
} | ||
if(!_valid_bounds(modulation.channelSpacing, modulationBounds.channelSpacing.min, modulationBounds.channelSpacing.max)) { | ||
res.result = false; | ||
return res; | ||
} | ||
if(!_valid_bounds(modulation.channelDeviation, modulationBounds.channelDeviation.min, modulationBounds.channelDeviation.max)) { | ||
res.result = false; | ||
return res; | ||
} | ||
return res; | ||
} | ||
}; | ||
return ( results.length > 0 ) ? results : true; | ||
} | ||
var prontoValidator = { | ||
cmds: function(cmds, signal) { | ||
var res = !Object.keys(cmds).some(function(cmd) { | ||
return !_valid_pronto_string(signal.cmds[cmd]); | ||
}); | ||
return {result: res, msg: 'invalid_pronto_cmd' }; | ||
}, | ||
repetitions: function(repetitions, signal) { | ||
var res = _valid_bounds(repetitions, rfBounds.repetitions.min, rfBounds.repetitions.max); | ||
return { result: res, msg: "repetitions_out_of_bounds" }; | ||
} | ||
}; | ||
SignalValidator.prototype.valid_433 = function( check ) { | ||
var modulation = ['ASK', 'FSK', 'PSK']; | ||
var defDefinition = { repetitions: 10, interval: 5000, | ||
rxTimeout: 0, rxBandwidth: 325000, deviation: 50000, | ||
modulation: modulation.indexOf('ASK'), carrier: 433920000 }; | ||
var rf433Bounds = { | ||
carrier: { min: 433000000, max: 433990000 } | ||
}; | ||
this.signal = extend(this.signal, defDefinition); | ||
var rf433Validator = { | ||
carrier: function(carrier, signal) { | ||
var res = _valid_bounds(carrier, 433000000, 433990000); | ||
return {result: res, msg: 'carrier_out_of_bounds' }; | ||
} | ||
}; | ||
// START 433 TESTS | ||
check( 'sensitivity_out_of_range', this.signal.sensitivity >= 0.1 && this.signal.sensitivity <= 1.0); | ||
check( 'repetitions_out_of_range', this.signal.repetitions >= 0 && this.signal.repetitions <= 255); | ||
check( 'interval_out_of_range', (this.signal.interval >= 50 && this.signal.interval <= 32767)); | ||
check( 'manchesterUnit_out_of_range', (this.signal.manchsterUnit == 0 || (this.signal.manchesterUnit >= 50 && this.signal.manchesterUnit <= 32767) )); | ||
check( 'frequency_out_of_range', this.signal.carrier >= 433000000 && this.signal.carrier <= 433990000); | ||
check( 'bandwidth_out_of_range', this.signal.rxBandwidth >= 58000 && this.signal.rxBandwidth <= 100000); | ||
check( 'deviation_out_of_range', this.signal.deviation >= 5000 && this.signal.deviation <= 100000); | ||
check( 'rxTimeout_out_of_range', this.signal.rxTimeout >= 0 && this.signal.rxTimeout <= 255); | ||
check( 'modulation_out_of_range', this.signal.modulation >= 0 && this.signal.rxTimeout <= 2); | ||
var rf868Bounds = { | ||
carrier: { min: 868000000, max: 868900000 } | ||
}; | ||
// END 433 TESTS | ||
} | ||
var rf868Validator = { | ||
carrier: function(carrier, signal) { | ||
var res = _valid_bounds(carrier, rf868Bounds.carrier.min, rf868Bounds.carrier.max); | ||
return {result: res, msg: "carrier_out_of_bounds" }; | ||
} | ||
}; | ||
SignalValidator.prototype.valid_868 = function( check ) { | ||
var modulation = ['ASK', 'FSK', 'PSK']; | ||
var defDefinition = { repetitions: 10, interval: 5000, | ||
rxTimeout: 0, rxBandwidth: 325000, deviation: 50000, | ||
modulation: modulation.indexOf('ASK'), carrier: 868200000 }; | ||
var irBounds = { | ||
carrier: { min: 30000, max: 45000 }, | ||
dutyCycle: { min: 30, max: 70 } | ||
}; | ||
// START 868 TESTS | ||
check( 'sensitivity_out_of_range', this.signal.sensitivity >= 0.1 && this.signal.sensitivity <= 1.0); | ||
check( 'repetitions_out_of_range', this.signal.repetitions >= 0 && this.signal.repetitions <= 255); | ||
check( 'interval_out_of_range', (this.signal.interval >= 50 && this.signal.interval <= 32767)); | ||
check( 'manchesterUnit_out_of_range', (this.signal.manchesterUnit >= 50 && this.signal.manchesterUnit <= 32767)); | ||
check( 'frequency_out_of_range', this.signal.carrier >= 868000000 && this.signal.carrier <= 868990000); | ||
check( 'bandwidth_out_of_range', this.signal.rxBandwidth >= 58000 && this.signal.rxBandwidth <= 100000); | ||
check( 'deviation_out_of_range', this.signal.deviation >= 5000 && this.signal.deviation <= 100000); | ||
check( 'rxTimeout_out_of_range', this.signal.rxTimeout >= 0 && this.signal.rxTimeout <= 255); | ||
check( 'modulation_out_of_range', this.signal.modulation >= 0 && this.signal.rxTimeout <= 2); | ||
// END 868 TESTS | ||
var irValidator = { | ||
carrier: function(carrier, signal) { | ||
var res = _valid_bounds(carrier, irBounds.carrier.min, irBounds.carrier.max); | ||
return { result: res, msg: "invalid_carrier"}; | ||
}, | ||
dutyCycle: function(dutyCycle, signal) { | ||
var res = _valid_bounds(dutyCycle, irBounds.dutyCycle.min, irBounds.dutyCycle.max); | ||
return { result: res, msg: "dutyCycle_out_of_bounds" }; | ||
} | ||
}; | ||
/* ---------------------- */ | ||
} | ||
SignalValidator.prototype.valid_ir = function( check ) { | ||
class SignalValidator { | ||
constructor( signal, opts ) { | ||
this.signal = signal; | ||
this.opts = Object.assign({ | ||
frequency: undefined // 433, 868, ir | ||
}, opts); | ||
this.results = []; | ||
this._check = this._check.bind(this); | ||
} | ||
_check(message, result) { | ||
if( result !== true ) this.results.push(message); | ||
} | ||
// START 868 TESTS | ||
check( 'bar' , this.signal.sof.length > 100 ); | ||
// END 868 TESTS | ||
valid() { | ||
this.results = []; | ||
switch(this.signal.type) { | ||
case 'prontohex': | ||
this._validPronto(this._check); | ||
break; | ||
case undefined: | ||
this._validRegular(this._check); | ||
break; | ||
default: | ||
this._check('invalid signal type', false); | ||
} | ||
this._check( 'invalid_frequency', typeof this[ '_valid_' + this.opts.frequency ] === 'function' ); | ||
if( typeof this[ '_valid_' + this.opts.frequency ] == 'function' ) { | ||
this[ '_valid_' + this.opts.frequency ](this._check); | ||
} | ||
return ( this.results.length > 0 ) ? this.results : true; | ||
} | ||
_validPronto(check) { | ||
// validate signal restrictions | ||
check( 'mandatory_fields', this.signal.hasOwnProperty('cmds') ); | ||
//validate generic signal | ||
_validate(prontoValidator, check, this.signal); | ||
} | ||
_validRegular(check) { | ||
// validate signal restrictions | ||
check( 'mandatory_fields', this.signal.hasOwnProperty('sof') || this.signal.hasOwnProperty('eof') || this.signal.hasOwnProperty('words') ); | ||
// do a generic signal check | ||
_validate(genericValidator, check, this.signal); | ||
_validate(rfValidator, check, this.signal); | ||
} | ||
/* Subdevice-specific validators */ | ||
_valid_433( check ) { | ||
// generic rf properties validation | ||
_validate(modulationValidator, check, this.signal); | ||
_validate(rf433Validator, check, this.signal); | ||
} | ||
_valid_868( check ) { | ||
// generic rf properties validation | ||
_validate(modulationValidator, check, this.signal); | ||
_validate(rf868Validator, check, this.signal); | ||
} | ||
_valid_ir( check ) { | ||
// check ir properties | ||
_validate(irValidator, check, this.signal); | ||
} | ||
} | ||
module.exports = SignalValidator; |
{ | ||
"name": "homey-signal-validator", | ||
"version": "1.0.0", | ||
"version": "2.0.0", | ||
"description": " Validator methods for Homey Signals", | ||
@@ -18,3 +18,6 @@ "main": "index.js", | ||
}, | ||
"homepage": "https://github.com/athombv/node-homey-signal-validator#readme" | ||
"homepage": "https://github.com/athombv/node-homey-signal-validator#readme", | ||
"engines" : { | ||
"node" : ">=4.0.0" | ||
} | ||
} |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
14036
6
405
2