2016-02-14 10:34:54 +01:00
function setOutValveTo ( controller _id , nextState ) {
2016-10-23 15:10:20 +02:00
var state = Meteor . zoblak . server . controller _state ( controller _id ) ;
2016-02-14 10:34:54 +01:00
ControllerState . update ( state . _id , {
'$set' : {
'state.out_valve' : nextState ,
'time' : new Date ( ) ,
'set_by' : 'server'
}
} ) ;
2016-05-08 05:17:12 +02:00
2016-07-02 10:18:18 +02:00
if ( nextState === "open" ) {
2016-05-08 05:17:12 +02:00
ControllerState . update ( state . _id , {
'$set' : {
'significantEvents.lastOutValveOpen' : new Date ( ) ,
}
} ) ;
}
2016-02-14 10:34:54 +01:00
}
2016-07-02 10:18:18 +02:00
function setInValveTo ( controller _id , nextState ) {
2016-10-23 15:10:20 +02:00
var state = Meteor . zoblak . server . controller _state ( controller _id ) ;
2016-07-02 10:18:18 +02:00
ControllerState . update ( state . _id , {
'$set' : {
'state.in_valve' : nextState ,
'time' : new Date ( ) ,
'set_by' : 'server'
}
} ) ;
if ( nextState === "open" ) {
ControllerState . update ( state . _id , {
'$set' : {
'significantEvents.lastInValveOpen' : new Date ( ) ,
}
} ) ;
}
}
2016-10-08 16:02:59 +02:00
function requestNewPicture ( controller _id ) {
2016-10-23 15:10:20 +02:00
var state = Meteor . zoblak . server . controller _state ( controller _id ) ;
2016-10-08 16:02:59 +02:00
ControllerState . update ( state . _id , {
'$set' : {
'state.picture_requested' : 'true' ,
'time' : new Date ( ) ,
'set_by' : 'server'
}
} ) ;
} ;
2016-07-02 10:18:18 +02:00
function openInValve ( controller _id ) {
2016-10-23 15:10:20 +02:00
var state = Meteor . zoblak . server . controller _state ( controller _id ) ;
2016-07-02 10:18:18 +02:00
var config = state . config ;
if ( config . manualInflow ) {
setInValveTo ( controller _id , 'opening' ) ;
}
reactToSensorData ( last _sensor _reading ( controller _id ) ) ;
}
function closeInValve ( controller _id ) {
2016-10-23 15:10:20 +02:00
var state = Meteor . zoblak . server . controller _state ( controller _id ) ;
2016-07-02 10:18:18 +02:00
var config = state . config ;
if ( config . manualInflow ) {
setInValveTo ( controller _id , 'closing' ) ;
}
reactToSensorData ( last _sensor _reading ( controller _id ) ) ;
}
2016-02-14 10:34:54 +01:00
function openOutValve ( controller _id ) {
setOutValveTo ( controller _id , 'opening' ) ;
2016-07-02 10:18:18 +02:00
setInValveTo ( controller _id , 'closing' ) ;
2016-10-23 15:10:20 +02:00
var state = Meteor . zoblak . server . controller _state ( controller _id ) ;
2016-02-14 10:34:54 +01:00
var config = state . config ;
var jobName = "Close out valve " + state . controller _id + " after draining" ;
console . log ( "Opening valve " , controller _id , jobName ) ;
SyncedCron . remove ( jobName ) ;
SyncedCron . add ( {
name : jobName ,
schedule : function ( parser ) {
var time = moment ( ) . add ( config . draining _period _amount , config . draining _period _unit ) . toDate ( ) ;
return parser . recur ( ) . on ( time ) . fullDate ( ) ;
} ,
job : function ( ) {
closeOutValve ( controller _id ) ;
}
} ) ;
2016-03-26 07:11:52 +01:00
console . log ( Meteor . sharedFunctions ) ;
2016-07-02 10:18:18 +02:00
reactToSensorData ( last _sensor _reading ( controller _id ) ) ;
2016-02-14 10:34:54 +01:00
}
function closeOutValve ( controller _id ) {
2016-10-23 15:10:20 +02:00
var state = Meteor . zoblak . server . controller _state ( controller _id ) ;
2016-02-14 10:34:54 +01:00
var jobName = "Close out valve " + state . controller _id + " after draining" ;
2016-02-28 10:05:14 +01:00
console . log ( "Closing valve " , controller _id , jobName ) ;
2016-02-14 10:34:54 +01:00
SyncedCron . remove ( jobName ) ;
setOutValveTo ( controller _id , 'closing' ) ;
console . log ( "Finished clearing cron " , controller _id ) ;
2016-03-26 07:11:52 +01:00
console . log ( Meteor . sharedFunctions ) ;
2016-07-02 10:18:18 +02:00
reactToSensorData ( last _sensor _reading ( controller _id ) ) ;
2016-02-14 10:34:54 +01:00
}
function clearLog ( ) {
console . log ( "Removing sensor data" ) ;
SensorData . remove ( { } ) ;
}
2016-07-02 10:18:18 +02:00
function saveControllerConfig ( controller _id , time , days , manualInflow ) {
2016-10-23 15:10:20 +02:00
var state = Meteor . zoblak . server . controller _state ( controller _id ) ;
2016-02-28 10:05:14 +01:00
ControllerState . update ( state . _id , {
'$set' : {
'config.automaticTimeOfDay' : time ,
2016-07-02 10:18:18 +02:00
'config.automaticDaysOfWeek' : days ,
'config.manualInflow' : manualInflow
2016-02-28 10:05:14 +01:00
}
} ) ;
var jobName = "automatic_" + controller _id ;
var times = time . split ( ":" ) ;
var hours = parseInt ( times [ 0 ] ) ;
var minutes = parseInt ( times [ 1 ] ) ;
SyncedCron . remove ( jobName ) ;
SyncedCron . add ( {
name : jobName ,
schedule : function ( parser ) {
var period = parser . recur ( ) ;
for ( var i = 0 ; i < days . length ; i ++ ) {
period = period . and ( ) . on ( parseInt ( days [ i ] ) ) . dayOfWeek ( ) . on ( hours ) . hour ( ) . on ( minutes ) . minute ( ) ;
}
return period ;
} ,
job : function ( ) {
openOutValve ( controller _id ) ;
}
} ) ;
}
2017-01-07 12:51:28 +01:00
function saveAlarmSettings ( controller _id , minTemperature , maxTemperature , timeoutBox , timeoutPhone , smsNumbers , sensorsEnabled ) {
2016-10-23 15:10:20 +02:00
var state = Meteor . zoblak . server . controller _state ( controller _id ) ;
ControllerState . update ( state . _id , {
'$set' : {
'config.minTemperature' : parseFloat ( minTemperature ) ,
'config.maxTemperature' : parseFloat ( maxTemperature ) ,
2016-11-19 08:03:54 +01:00
'config.timeoutBox' : timeoutBox ? parseInt ( timeoutBox ) : null ,
'config.timeoutPhone' : timeoutPhone ? parseInt ( timeoutPhone ) : null ,
2016-10-23 15:10:20 +02:00
'config.smsNumbers' : smsNumbers ,
'config.sms1' : smsNumbers [ 0 ] ,
'config.sms2' : smsNumbers [ 1 ] ,
'config.sms3' : smsNumbers [ 2 ] ,
2017-01-07 12:51:28 +01:00
'config.sms4' : smsNumbers [ 3 ] ,
'config.sensorsEnabled' : sensorsEnabled
2016-10-23 15:10:20 +02:00
}
} ) ;
2017-01-06 18:36:57 +01:00
2016-10-23 15:10:20 +02:00
var jobName = "automatic_alarm_" + controller _id ;
SyncedCron . remove ( jobName ) ;
SyncedCron . add ( {
name : jobName ,
schedule : function ( parser ) {
2016-11-19 08:03:54 +01:00
return parser . text ( 'every 10 seconds' ) ;
2016-10-23 15:10:20 +02:00
} ,
job : function ( ) {
reactToAlarmData ( controller _id ) ;
}
} ) ;
2016-11-16 14:03:03 +01:00
reactToAlarmData ( controller _id ) ;
2016-10-23 15:10:20 +02:00
}
2016-10-23 15:57:04 +02:00
// there are three states of alarm:
// 1. normal ( state.alarmTriggered: false, state.alarmStopped: null )
// 2. triggered ( state.alarmTriggered: true, state.alarmStopped: null )
// 3. silenced ( state.alarmTriggered: false, state.alarmStopped: (sometime) )
2016-11-16 14:03:03 +01:00
reactToAlarmData = function ( controller _id ) {
2016-10-23 15:10:20 +02:00
var reading = last _sensor _reading ( controller _id ) ;
var state = Meteor . zoblak . server . controller _state ( controller _id ) ;
var config = state . config ;
2017-01-06 18:36:57 +01:00
2016-10-23 15:10:20 +02:00
var minTemperature = function ( temperatures ) {
2016-11-16 14:03:03 +01:00
// if it gets a lot colder than absolute zero
2016-10-23 15:10:20 +02:00
// we will have more problems than the bug in this code
2016-10-23 15:57:04 +02:00
if ( temperatures . length <= 0 ) return - 1000 ;
2016-10-23 15:10:20 +02:00
var minimal = parseFloat ( temperatures [ 0 ] ) ;
for ( var i in temperatures ) {
if ( parseFloat ( temperatures [ i ] ) < minimal ) {
minimal = parseFloat ( temperatures [ i ] ) ;
}
}
return minimal ;
2017-01-06 18:36:57 +01:00
} ;
2016-10-23 15:10:20 +02:00
var maxTemperature = function ( temperatures ) {
// obviously - hell is not supported in this version
2016-10-23 15:57:04 +02:00
if ( temperatures . length <= 0 ) return 1000 ;
2016-10-23 15:10:20 +02:00
var maximal = parseFloat ( temperatures [ 0 ] ) ;
for ( var i in temperatures ) {
if ( parseFloat ( temperatures [ i ] ) > maximal ) {
maximal = parseFloat ( temperatures [ i ] ) ;
}
}
return maximal ;
2017-01-06 18:36:57 +01:00
} ;
2017-01-07 13:05:31 +01:00
var temperatures = ( reading . temperatures || [ ] ) . filter ( function ( temperature , index ) {
2017-01-07 13:07:24 +01:00
var is _on = ( index in config . sensorsEnabled ) ? config . sensorsEnabled [ index ] : true ;
return Meteor . zoblak . shared . valid _temperature ( temperature ) && is _on ;
2017-01-07 13:05:31 +01:00
} ) ;
2017-05-21 17:51:45 +02:00
console . log ( "Konfiguracija: " , controller _id , config ) ;
2016-10-23 15:10:20 +02:00
2017-01-06 18:36:57 +01:00
var tooCold = config . minTemperature && ( minTemperature ( temperatures ) < config . minTemperature ) ;
2016-10-23 15:10:20 +02:00
2017-01-06 18:36:57 +01:00
var tooHot = config . maxTemperature && ( maxTemperature ( temperatures ) > config . maxTemperature ) ;
2016-10-23 15:10:20 +02:00
2016-10-29 13:07:08 +02:00
var minutesSinceLastBoxContact = reading . lastBoxContact ? moment ( new Date ( ) ) . diff ( moment ( reading . lastBoxContact ) , 'minutes' ) : - 1 ;
2016-10-23 15:10:20 +02:00
var boxSilent = config . timeoutBox && minutesSinceLastBoxContact > config . timeoutBox ;
2016-10-29 13:07:08 +02:00
var minutesSinceLastPhoneContact = state . lastPhoneContact ? moment ( new Date ( ) ) . diff ( moment ( state . lastPhoneContact ) , 'minutes' ) : - 1 ;
2017-01-05 15:12:40 +01:00
var phoneSilent = false ; //config.timeoutPhone && minutesSinceLastPhoneContact > config.timeoutPhone;
2016-10-23 15:10:20 +02:00
2016-11-16 14:03:03 +01:00
console . log ( "too " , tooCold , tooHot , boxSilent , phoneSilent ) ;
2016-10-29 13:07:08 +02:00
console . log ( "lpc" , state . lastPhoneContact ) ;
console . log ( "mslpc" , minutesSinceLastPhoneContact ) ;
console . log ( "phoneSilent" , phoneSilent ) ;
2016-10-23 15:57:04 +02:00
2016-10-23 15:10:20 +02:00
if ( tooCold || tooHot || boxSilent || phoneSilent ) {
2016-10-23 15:57:04 +02:00
var alarmSilenced = ! ! state . state . alarmStopped ;
if ( ! alarmSilenced ) soundTheAlarm ( controller _id , tooCold , tooHot , boxSilent , phoneSilent ) ;
} else {
stopTheAlarm ( controller _id , true ) ;
2016-10-23 15:10:20 +02:00
}
}
2016-10-23 15:57:04 +02:00
function soundTheAlarm ( controller _id , tooCold , tooHot , boxSilent , phoneSilent ) {
2016-10-23 15:10:20 +02:00
var state = Meteor . zoblak . server . controller _state ( controller _id ) ;
var reason = {
tooHot : tooHot ,
tooCold : tooCold ,
boxSilent : boxSilent ,
phoneSilent : phoneSilent
} ;
2016-10-29 13:07:08 +02:00
console . log ( "Alarmiram" , reason ) ;
2016-10-23 15:10:20 +02:00
2016-10-29 13:07:08 +02:00
var firstTime = { } ;
2016-10-23 15:10:20 +02:00
if ( ! state . state . alarmTriggered ) {
2016-10-29 13:07:08 +02:00
firstTime = {
'state.alarmStarted' : new Date ( )
2016-10-23 15:10:20 +02:00
}
2016-10-29 13:07:08 +02:00
} ;
var smsSent = ! ! state . state . alarmSmsSent ;
2016-12-30 17:18:04 +01:00
var needsToSendSms = ! smsSent // && phoneSilent;
2016-10-29 13:07:08 +02:00
2017-01-05 15:12:40 +01:00
var sendSmsPart = needsToSendSms ? {
'state.alarmSmsSent' : true
} : { } ;
2016-10-29 13:07:08 +02:00
ControllerState . update ( state . _id , {
'$set' : Object . assign ( {
'state.alarmTriggered' : true ,
'state.alarmStopped' : null ,
'state.alarmReasons' : reason
} , firstTime , sendSmsPart )
} ) ;
if ( needsToSendSms ) {
2017-01-05 15:12:40 +01:00
sendAlarmingSms ( controller _id , reason , state . config . smsNumbers ) ;
callTheUser ( controller _id , reason , state . config . smsNumbers ) ;
2016-10-23 15:10:20 +02:00
}
}
2017-01-05 15:12:40 +01:00
function sendAlarmingSms ( controller _id , reason , numbers ) {
2016-10-23 15:10:20 +02:00
for ( var i in numbers ) {
var number = numbers [ i ] ;
twilio = Twilio ( 'AC10d7ed0bf54c1be4b1cd7133130e63f4' , 'e133d3f02a69b79e93ad9ca1d73517d1' ) ;
twilio . sendSms ( {
to : number , // Any number Twilio can deliver to
2017-01-05 15:12:40 +01:00
from : '+19282124174' , // A number you bought from Twilio and can use for outbound communication
2016-12-30 17:22:51 +01:00
body : 'Zoblak alarm! Pokrenite aplikaciju! HITNO! http://agrar.zoblak.com/alarm?controller_id=' + controller _id // body of the SMS message
2016-10-23 15:10:20 +02:00
} , function ( err , responseData ) { //this function is executed when a response is received from Twilio
if ( ! err ) { // "err" is an error received during the request, if any
// "responseData" is a JavaScript object containing data received from Twilio.
// A sample response from sending an SMS message is here (click "JSON" to see how the data appears in JavaScript):
// http://www.twilio.com/docs/api/rest/sending-sms#example-1
console . log ( responseData . from ) ; // outputs "+14506667788"
console . log ( responseData . body ) ; // outputs "word to your mother."
}
} ) ;
}
}
2017-01-05 15:12:40 +01:00
function callTheUser ( controller _id , reason , numbers ) {
for ( var i in numbers ) {
var number = numbers [ i ] ;
twilio = Twilio ( 'AC10d7ed0bf54c1be4b1cd7133130e63f4' , 'e133d3f02a69b79e93ad9ca1d73517d1' ) ;
twilio . makeCall ( {
to : number , // Any number Twilio can call
from : '+441143031932' , // A number you bought from Twilio and can use for outbound communication
url : 'https://handler.twilio.com/twiml/EH9491c24474db07ec52b598baa5724f1e' // A URL that produces an XML document (TwiML) which contains instructions for the call
} , function ( err , responseData ) {
//executed when the call has been initiated.
console . log ( err ) ; // outputs "+14506667788"
} ) ;
}
}
2016-10-23 15:57:04 +02:00
function stopTheAlarm ( controller _id , everythingIsBackToNormal = false ) {
// time of alarm stopped is reset so that scheduled job can raise the alarm
// again
var timeOfStopping = ( everythingIsBackToNormal ) ? null : new Date ( ) ;
var state = Meteor . zoblak . server . controller _state ( controller _id ) ;
ControllerState . update ( state . _id , {
'$set' : {
'state.alarmTriggered' : false ,
2016-10-29 13:07:08 +02:00
'state.alarmStopped' : timeOfStopping ,
'state.alarmSmsSent' : false
2016-10-23 15:57:04 +02:00
}
} ) ;
}
2016-03-26 07:11:52 +01:00
function last _sensor _reading ( controller _id ) {
var result = null ;
if ( controller _id ) {
result = SensorData . find ( {
controllerId : controller _id
} , {
sort : {
created _at : - 1
} ,
limit : 1
} ) ;
}
if ( result && result . count ( ) > 0 ) {
return result . fetch ( ) [ 0 ] ;
} else {
return { }
}
}
2016-02-14 10:34:54 +01:00
Meteor . methods ( {
openOutValve : openOutValve ,
closeOutValve : closeOutValve ,
2016-07-02 10:18:18 +02:00
openInValve : openInValve ,
closeInValve : closeInValve ,
2016-02-28 10:05:14 +01:00
clearLog : clearLog ,
2016-10-08 16:02:59 +02:00
saveControllerConfig : saveControllerConfig ,
2016-10-23 15:10:20 +02:00
requestNewPicture : requestNewPicture ,
2016-10-23 15:57:04 +02:00
saveAlarmSettings : saveAlarmSettings ,
stopTheAlarm : stopTheAlarm
2016-02-14 10:34:54 +01:00
} ) ;