Better handling of fuzzify allowing events to be run in fuzzy interval, even if job is loaded after the execution time, and not rerun if already executed in the interval already (implementing lastRun)

This commit is contained in:
Stefan Persson 2011-02-14 13:16:30 +00:00
parent 0ec9cc99cf
commit 23fd9d5da7
7 changed files with 163 additions and 57 deletions

View file

@ -8,7 +8,7 @@ com.telldus.scheduler.EVENTTYPE_SUNRISE = 1;
com.telldus.scheduler.EVENTTYPE_SUNSET = 2;
function getEventRunTime(event, date){
function getEventRunTime(event, date, lastRun){
var currentEventRuntimeTimestamp = null;
var offset = event.d.offset;
if(isNaN(offset)){
@ -22,13 +22,13 @@ function getEventRunTime(event, date){
//print("currentEventRuntimeTimestamp: " + new Date(currentEventRuntimeTimestamp));
currentEventRuntimeTimestamp += (offset * 1000); //this is really not useful for absolute values, but exists for consistency
//print("currentEventRuntimeTimestamp1: " + new Date(currentEventRuntimeTimestamp));
currentEventRuntimeTimestamp = com.telldus.scheduler.fuzzify(currentEventRuntimeTimestamp, parseInt(event.d.fuzzinessBefore), parseInt(event.d.fuzzinessAfter));
currentEventRuntimeTimestamp = com.telldus.scheduler.fuzzify(currentEventRuntimeTimestamp, parseInt(event.d.fuzzinessBefore), parseInt(event.d.fuzzinessAfter), lastRun);
//print("currentEventRuntimeTimestamp2: " + new Date(currentEventRuntimeTimestamp));
}
else if(event.d.type == com.telldus.scheduler.EVENTTYPE_SUNRISE || event.d.type == com.telldus.scheduler.EVENTTYPE_SUNSET){
currentEventRuntimeTimestamp = getSunUpDownForDate(date, parseInt(event.d.type));
currentEventRuntimeTimestamp += (offset * 1000);
currentEventRuntimeTimestamp = com.telldus.scheduler.fuzzify(currentEventRuntimeTimestamp, parseInt(event.d.fuzzinessBefore), parseInt(event.d.fuzzinessAfter));
currentEventRuntimeTimestamp = com.telldus.scheduler.fuzzify(currentEventRuntimeTimestamp, parseInt(event.d.fuzzinessBefore), parseInt(event.d.fuzzinessAfter), lastRun);
}
return currentEventRuntimeTimestamp;
@ -84,14 +84,15 @@ function getJob(jobdata){
* but wasn't, because of a reboot or similar (in seconds)
* note, must in that case have checked last run
*/
function getNextEventRunTime(nextRunTime, event, date, pastGracePeriod){
function getNextEventRunTime(nextRunTime, event, date, pastGracePeriod, lastRun){
if(!pastGracePeriod){
var pastGracePeriod = 0;
}
var currentEventRuntimeTimestamp = getEventRunTime(event, date);
var currentEventRuntimeTimestamp = getEventRunTime(event, date, lastRun);
print("EventRunTime: " + new Date(currentEventRuntimeTimestamp));
if((nextRunTime === null || currentEventRuntimeTimestamp < nextRunTime) && currentEventRuntimeTimestamp > (new Date().getTime() - pastGracePeriod)){ //earlier than other events, but later than "now"
nextRunTime = currentEventRuntimeTimestamp;
}
@ -136,6 +137,7 @@ function getSunUpDownForDate(datetimestamp, sun){
return date.getTime();
}
/*
function loadJobs(){
print("Loading jobs");
//TODO detta ska inte göras från denna plugin, utan från respektive...
@ -176,7 +178,8 @@ function loadJobs(){
var tempkey = com.telldus.scheduler.addJob(job); //TODO, use different function than this = only sort list afterwards (one time) and dont start timer until all initial are added
}
*/
}
//}
/*
* updateLastRun-example:
@ -296,7 +299,7 @@ com.telldus.scheduler.JobAbsolute.prototype.getNextRunTime = function(){
var pastGracePeriod = getGracePeriod(this.v);
for(var key in this.v.events){
nextRunTime = getNextEventRunTime(nextRunTime, this.v.events[key], 0, pastGracePeriod);
nextRunTime = getNextEventRunTime(nextRunTime, this.v.events[key], 0, pastGracePeriod, this.v.lastRun);
}
return nextRunTime;
}
@ -310,7 +313,7 @@ com.telldus.scheduler.JobRecurringDay.prototype.getNextRunTime = function(){
var date;
if(this.v.lastRun > 0){
var lastRunDate = new Date(this.lastRun);
var lastRunDate = new Date(this.v.lastRun); //TEST changed from this.lastRun, test this!
date = new Date(lastRunDate.getFullYear(), lastRunDate.getMonth(), lastRunDate.getDate());
date = date.getTime() + this.v.events[0].d.value; //add interval
}
@ -324,11 +327,11 @@ com.telldus.scheduler.JobRecurringDay.prototype.getNextRunTime = function(){
}
date = new Date(startTime.getFullYear(), startTime.getMonth(), startTime.getDate());
}
nextRunTime = getNextEventRunTime(null, this.v.events[0], date.getTime(), pastGracePeriod);
nextRunTime = getNextEventRunTime(null, this.v.events[0], date.getTime(), pastGracePeriod, this.v.lastRun);
if(nextRunTime < new Date().getTime()){
var runTime = new Date(date);
runTime.setDate(runTime.getDate() + parseInt(this.v.events[0].d.value));
nextRunTime = getNextEventRunTime(null, this.v.events[0], runTime.getTime(), pastGracePeriod); //already passed this time today, try again after "interval" days
nextRunTime = getNextEventRunTime(null, this.v.events[0], runTime.getTime(), pastGracePeriod, this.v.lastRun); //already passed this time today, try again after "interval" days
}
return nextRunTime;
@ -363,10 +366,10 @@ com.telldus.scheduler.JobRecurringWeek.prototype.getNextRunTime = function(){
returnDate = zeroTime(returnDate);
nextTempRunTime = getNextEventRunTime(nextRunTime, this.v.events[key], returnDate.getTime(), pastGracePeriod);
nextTempRunTime = getNextEventRunTime(nextRunTime, this.v.events[key], returnDate.getTime(), pastGracePeriod, this.v.lastRun);
if(nextTempRunTime < new Date().getTime()){ //event happened today, already passed, add to next week instead
returnDate.setDate(returnDate.getDate() + 7);
nextRunTime = getNextEventRunTime(nextRunTime, this.v.events[key], returnDate.getTime(), pastGracePeriod);
nextRunTime = getNextEventRunTime(nextRunTime, this.v.events[key], returnDate.getTime(), pastGracePeriod, this.v.lastRun);
}
else{
nextRunTime = nextTempRunTime;

View file

@ -35,7 +35,6 @@ com.telldus.scheduler = function() {
}
var key = storedJobs.push(job);
job.key = key;
print("Add job");
updateJobInList(key);
return key;
}
@ -61,8 +60,19 @@ com.telldus.scheduler = function() {
return returnKeys;
}
function fuzzify(currentTimestamp, fuzzinessBefore, fuzzinessAfter){
function fuzzify(currentTimestamp, fuzzinessBefore, fuzzinessAfter, lastRun){
if(fuzzinessAfter != 0 || fuzzinessBefore != 0){
var now = new Date().getTime();
if(currentTimestamp - (fuzzinessBefore*1000) < now){
fuzzinessBefore = (currentTimestamp - now)/1000; //we have already entered the fuzzy-interval, move the start point to "now"...
}
//print("LASTRUN: " + new Date(lastRun));
//print("COMPARE: " + new Date(currentTimestamp - (fuzzinessBefore*1000)));
if(lastRun != undefined && lastRun >= (currentTimestamp - (fuzzinessBefore*1000))){
//print("JUST RETURNING");
return 0; //job already run in this interval, don't run it again...
}
//print("CONTINUING HAPPILY");
var interval = fuzzinessAfter + fuzzinessBefore;
var rand = Math.random(); //Random enough at the moment
var fuzziness = Math.floor((interval+1) * rand);
@ -312,9 +322,20 @@ com.telldus.scheduler.Job.prototype.execute = function(){
return success;
}
success = this.executeDefault();
//if(success){
//update last run even if not successful, else it may become an infinite loop (if using pastGracePeriod)
this.updateJobLastRun();
//}
return success;
};
com.telldus.scheduler.Job.prototype.executeDefault = function(){
var success = 0;
deviceid = this.v.device;
var method = parseInt(this.v.method);
print("Job id: " + this.v.device + " Method: " + method);
//print("Job id: " + this.v.device + " Method: " + method);
switch(method){
case com.telldus.core.TELLSTICK_TURNON:
success = com.telldus.core.turnOn(deviceid);
@ -331,10 +352,6 @@ com.telldus.scheduler.Job.prototype.execute = function(){
default:
break;
}
//if(success){
//update last run even if not successful, else it may become an infinite loop (if using pastGracePeriod)
this.updateJobLastRun();
//}
return success;
};

View file

@ -18,6 +18,8 @@ Rectangle{
property int absoluteMinute: parseInt(dialog.absoluteMinute, 10)
property alias triggerstate: trigger.state
property variant parentPoint
property variant pointId
property variant lastRun: 0;
//property int parentPointAbsoluteHour //TEST changed from int, want "undefined"
property alias deviceRow: pointRect.parent

View file

@ -47,6 +47,11 @@
}
event.accepted = true;
}
else if( event.key == Qt.Key_Delete){
//TODO warning?
container.actionPoint.remove();
}
else{
return;
}

View file

@ -20,7 +20,8 @@ com.telldus.schedulersimplegui = function() {
getSunSetTime: getSunSetTime,
getSunData: getSunData,
getTypeFromTriggerstate: getTypeFromTriggerstate,
getTriggerstateFromType: getTriggerstateFromType
getTriggerstateFromType: getTriggerstateFromType,
restoreJobs: restoreJobs
});
//devices:
@ -36,8 +37,8 @@ com.telldus.schedulersimplegui = function() {
//Listen for device-change
com.telldus.core.deviceChange.connect(deviceChange);
var storedPoints = loadJobs();
view.setProperty('storedPoints', storedPoints);
//var storedPoints = loadJobs();
//view.setProperty('storedPoints', storedPoints);
//set images:
view.setProperty("imageTriggerSunrise", "sunrise.png");
@ -72,7 +73,7 @@ com.telldus.schedulersimplegui = function() {
}
}
function addJobsToSchedule(deviceId, points, deviceTimerKeys){
function addJobsToSchedule(deviceId, points, deviceTimerKeys, callbackFunc){
//delete all current schedules for this device:
if(deviceTimerKeys != undefined){
for(var i=0;i<deviceTimerKeys.length;i++){
@ -84,7 +85,7 @@ com.telldus.schedulersimplegui = function() {
//add new schedules:
var jobs = new Array();
for(var i=0;i<points.length;i++){
var jobtemp = getJob(points[i]);
var jobtemp = getJob(points[i], callbackFunc);
jobs.push(jobtemp);
}
print("Adding some jobs " + jobs.length);
@ -104,46 +105,91 @@ com.telldus.schedulersimplegui = function() {
settings.setValue("jobs", jobs);
}
function loadJobs(){
function loadJobs(updateLastRun){
var settings = new com.telldus.settings();
var temp = settings.value("jobs", "");
return settings.value("jobs", "");
/*
//from storage...
var weekPointList = new com.telldus.qml.array();
var dummypoint = {};
dummypoint["day"] = 0;
dummypoint["deviceId"] = 1;
weekPointList.push(dummypoint);
dummypoint = {};
dummypoint["day"] = 1;
dummypoint["deviceId"] = 2;
weekPointList.push(dummypoint);
*/
var storedJobs = settings.value("jobs", "");
restoreJobsToSchedule(storedJobs, updateLastRun); //Start timers here
return storedJobs;
}
function getJob(pointArray){ //deviceId, pointName, startdate, lastrun, pointMethod, pointDimValue, pointTime, pointType, pointFuzzinessBefore, pointFuzzinessAfter, pointOffset, pointDays
//var execFunc = function(job){ print("Custom execute function running"); print("Job: " + job.v.name); return 42; }; //TODO default later
//TODO dimValue 0-100 ok? Or other number expected?
var job = new com.telldus.scheduler.JobRecurringWeek({id: pointArray[0], executeFunc: null, name: pointArray[1], type: com.telldus.scheduler.JOBTYPE_RECURRING_WEEK, startdate: pointArray[2], lastRun: pointArray[3], device: pointArray[0], method: pointArray[4], value: pointArray[5], absoluteTime: pointArray[12]});
function restoreJobsToSchedule(storedJobs, updateLastRun){
var jobs = new Array();
for(var devicekey in storedJobs){
for(var i=0;i<storedJobs[devicekey].length;i++){
if(storedJobs[devicekey][i] == undefined){
continue;
}
var jobtemp = restoreJob(storedJobs[devicekey][i], updateLastRun);
jobs.push(jobtemp);
}
}
return com.telldus.scheduler.addJobs(jobs)
}
function restoreJob(storedJob, updateLastRunInGUI){
var execFunc = function(job){ print("Custom execute function running"); print("Job: " + job.v.name); var lastRun = new Date().getTime(); updateLastRun(job, lastRun); updateLastRunInGUI(job.v.device, job.v.events[job.v.id + "_0"].d.value, job.v.id, lastRun); return job.executeDefault();};
var job = new com.telldus.scheduler.JobRecurringWeek(storedJob.v);
job.v.executeFunc = execFunc;
return job;
}
function restoreJobs(updateLastRun){
var storedPoints = loadJobs(updateLastRun);
view.setProperty('storedPoints', storedPoints);
}
function getJob(pointArray, updateLastRunInGUI){ //deviceId, pointName, startdate, lastrun, pointMethod, pointDimValue, pointTime, pointType, pointFuzzinessBefore, pointFuzzinessAfter, pointOffset, pointDays
//updateLastRunInGUI: deviceId, day of week, id
var execFunc = function(job){ print("Custom execute function running"); print("Job: " + job.v.name); var lastRun = new Date().getTime(); updateLastRun(job, lastRun); updateLastRunInGUI(job.v.device, job.v.events[job.v.id + "_0"].d.value, job.v.id, lastRun); return job.executeDefault();};
print("POINTARRAY3: " + pointArray[3]);
var job = new com.telldus.scheduler.JobRecurringWeek({id: pointArray[13], executeFunc: execFunc, name: pointArray[1], type: com.telldus.scheduler.JOBTYPE_RECURRING_WEEK, startdate: pointArray[2], lastRun: pointArray[3], device: pointArray[0], method: pointArray[4], value: pointArray[5], absoluteTime: pointArray[12]});
var event = {};
var pointFuzzinessBefore = (pointArray[8]*60);
var pointFuzzinessAfter = (pointArray[9]*60);
var pointOffset = (pointArray[10]*60);
event.d = {id: (pointArray[0] + "_0"), value: pointArray[11][0], fuzzinessBefore: pointFuzzinessBefore, fuzzinessAfter: pointFuzzinessAfter, type: pointArray[7], offset: pointOffset, time: pointArray[6]};
event.d = {id: (pointArray[13] + "_0"), value: pointArray[11][0], fuzzinessBefore: pointFuzzinessBefore, fuzzinessAfter: pointFuzzinessAfter, type: pointArray[7], offset: pointOffset, time: pointArray[6]};
job.addEvent(event);
for(var i=1;i<pointArray[11].length;i++){
event = {};
pointDay = pointArray[11][i];
event.d = {id: (pointArray[0] + "_" + i), value: pointDay, fuzzinessBefore: pointFuzzinessBefore, fuzzinessAfter: pointFuzzinessAfter, type: pointArray[7], offset: pointOffset, time: pointArray[6]};
event.d = {id: (pointArray[13] + "_" + i), value: pointDay, fuzzinessBefore: pointFuzzinessBefore, fuzzinessAfter: pointFuzzinessAfter, type: pointArray[7], offset: pointOffset, time: pointArray[6]};
job.addEvent(event);
}
return job;
}
function updateLastRun(job, lastRun){
//TODO uppdatera både storage och värdet i pointen...
var settings = new com.telldus.settings();
var storedjobs = settings.value("jobs", "");
//settings.setValue("test", "TESTAR");
print("UPDATING LAST RUN 3 " + storedjobs);
for(var devicekey in storedjobs){
print("Key: " + devicekey);
if(devicekey == job.v.device){
print("En bra bit");
for(var i=0;i<storedjobs[devicekey].length;i++){
print("GREJ 2: " + storedjobs[devicekey][i].v.id);
print("JMF: " + job.v.id);
if(storedjobs[devicekey][i].v.id == job.v.id){
storedjobs[devicekey][i].v.lastRun = lastRun;
break;
}
}
break;
}
}
settings.setValue("jobs", storedjobs);
print("saveD");
//för alla points denna... device och dag (parentpointens dag, dvs det som är lagrat i job)
//gå igenom punkterna, hitta punkt med korrekt id, uppdatera last run för den...
}
function getMethodFromState(state){
var pointMethod = "";
if(state == "on"){

View file

@ -28,6 +28,8 @@ import "schedulerscripts.js" as Scripts
weekDayText.text = Scripts.getCurrentDayName()
//Scripts.updateDeviceIndex();
Scripts.setLoading();
var updateLastRunFunc = updateLastRun;
restoreJobs.callWith(updateLastRunFunc);
Scripts.initiateStoredPointsInGUI();
Scripts.endLoading();
Scripts.updateEndsWith();
@ -304,6 +306,7 @@ import "schedulerscripts.js" as Scripts
dynamicPoint.addActiveState("bell");
//dynamicPoint.setFirstState("dim"); //when type is a stored value
dynamicPoint.setFirstState();
dynamicPoint.pointId = new Date().getTime(); //just needed for storage update
//TEST, proof of concept for repeat-everyday-points:
@ -573,18 +576,28 @@ import "schedulerscripts.js" as Scripts
}
var deviceTimerKeys = Scripts.getDeviceTimerKeys(deviceId); //get timer keys for this device, for removal
deviceTimerKeys = addJobsToSchedule.callWith(deviceId, points, deviceTimerKeys); //remove all schedules for this device, and add them again
var updateLastRunFunc = updateLastRun;
deviceTimerKeys = addJobsToSchedule.callWith(deviceId, points, deviceTimerKeys, updateLastRunFunc); //remove all schedules for this device, and add them again
Scripts.setDeviceTimerKeys(deviceId, deviceTimerKeys); //save the new timer keys
}
}
function updateLastRun(deviceId, day, pointId, lastRun){
print("deviceid: " + deviceId);
print("day: " + day);
print("pointid: " + pointId);
Scripts.updateLastRun(deviceId, day, pointId, lastRun);
}
function pointToArray(point){ //TODO another way than using arrays...
var deviceId = point.deviceRow.deviceId; //not really in use yet
var pointName = "Job_" + deviceId;
var lastrun = 0; //TODO
var startdate = new Date(); //startdate, not in use, always "now"
var pointDimValue = point.dimvalue;
var pointDimValue = point.dimvalue * (255/100);
var pointMethod = getMethodFromState.callWith(point.state);
var pointId = point.pointId;
var lastRun = point.lastRun;
print("LASTRUN pointToArray: " + lastRun);
var pointTime = point.absoluteHour * 3600 + point.absoluteMinute * 60;
var absolutePointTime = pointTime;
@ -608,6 +621,6 @@ import "schedulerscripts.js" as Scripts
pointDays.push(childPoints[child].deviceRow.parent.parent.daydate.getDay()); //different per event
print("GOT DAY " + childPoints[child].deviceRow.parent.parent.daydate.getDay());
}
return new Array(deviceId, pointName, startdate, lastrun, pointMethod, pointDimValue, pointTime, pointType, pointFuzzinessBefore, pointFuzzinessAfter, pointOffset, pointDays, absolutePointTime);
return new Array(deviceId, pointName, startdate, lastRun, pointMethod, pointDimValue, pointTime, pointType, pointFuzzinessBefore, pointFuzzinessAfter, pointOffset, pointDays, absolutePointTime, pointId);
}
}

View file

@ -312,11 +312,8 @@ function assignContinuingBarProperties(deviceRow, previousEndPoint, dayIndex, fi
//Init:
function initiateStoredPointsInGUI(){
var k = 0;
for(var devicekey in storedPoints){
for(var i=0;i<storedPoints[devicekey].length;i++){
k++;
print("ADDED POINTS: " + k);
addPointToGUI(devicekey, storedPoints[devicekey][i]);
}
}
@ -332,6 +329,9 @@ function addPointToGUI(key, job){
var activeStates = new Array("on", "off", "dim", "bell"); //TODO get dynamically, depending on device...
var dimvalue = jobdata.value;
var absoluteTime = jobdata.absoluteTime;
var pointId = jobdata.id;
var lastRun = jobdata.lastRun;
print("Adding point to GUI with lastrun: " + lastRun);
var events = jobdata.events;
var parentPoint;
@ -355,14 +355,16 @@ function addPointToGUI(key, job){
dynamicPoint.triggerstate = getTriggerstateFromType.callWith(eventdata.type);
dynamicPoint.fuzzyBefore = eventdata.fuzzinessBefore/60;
dynamicPoint.fuzzyAfter = eventdata.fuzzinessAfter/60;
dynamicPoint.offset = eventdata.offset;
dynamicPoint.offset = eventdata.offset/60;
dynamicPoint.lastRun = lastRun;
if(dynamicPoint.triggerstate == "absolute"){
dynamicPoint.x = dynamicPoint.getAbsoluteXValue();
}
dynamicPoint.setActiveStates(activeStates); //TODO: active states depending on the device (get this from __init__ etc)
dynamicPoint.setFirstState(state);
dynamicPoint.dimvalue = dimvalue;
dynamicPoint.dimvalue = dimvalue * (100/255);
dynamicPoint.pointId = pointId;
print("SETTING POINTID TO: " + pointId);
parentPoint = dynamicPoint;
}
else{
@ -526,7 +528,7 @@ function getOffsetWeekdayName(index){
}
function getOffsetWeekday(index){
//TODO this can be modified based on locale, not adding 1 of week should start with sunday
//TODO this can be modified based on locale, not adding 1 if week should start with sunday
index = parseInt(index);
index = index + 1;
if(index == weekday_name_array.length){
@ -535,6 +537,24 @@ function getOffsetWeekday(index){
return index;
}
function updateLastRun(deviceId, day, pointId, lastRun){
print("0");
day = getDayIndexForDayOfWeek(day);
print("1: " + day);
var row = getDeviceRow(day,deviceId);
print("2: " + row);
for(var k=0;k<row.children.length;k++){
print("3: " + row.children[k]);
var point = row.children[k];
if(point.isPoint && point.parentPoint == undefined && point.pointId == pointId){ //and not disabled
print("UPDATING LAST RUN, " + lastRun);
point.lastRun = lastRun;
print("IS, " + point.lastRun);
}
}
}
//TODO move, pragma safe:
function getFirstPointWidth(deviceRow){
var pointList = deviceRow.children; //TODO should really try to avoid using "children"... make own list instead?