Alarms in NodeJS (without any delay) - javascript

I am currently attempting to make an alarm system for a website that I control my sprinklers with.
Currently, I use sockets to get alarms from the client and store them in a JSON file in the server.
To "activate" the alarms, I have thought to have a setInterval function that checks whether the current time is included in the array (using .includes() )
I am very annooyed currently because the setInterval function is delays 65 milliseconds every time it is run
Does it wait for the code inside to finish before continuing? If so, how do I make it not do so
This is my code:
I think this may be relevant, if I could understand it (I am new)
console.log("Waiting for time to get in to sync...")
while (sync > 0 || sync == undefined) {
let date = new Date()
sync = date.getSeconds()
}
setInterval(()=>{
check(new Date()) //run the check code elsewhere
}, 60000); // one minute delay```

Related

Interval synced to Time

I want to execute a function in an interval. Yeah I could use setInterval but I need the interval to be synced to the timestamp or something.
Like I want to execute the interval on two different devices and they should run in the exact same second or even ms if possible. But depending on when I star the script these intervals would be offset if I would use setInterval method.
I've already tried this but it kinda acts weird.
setInterval(() => {
if (new Date().getTime() % 1000 * 10 == 0) {
console.log(new Date().toLocaleTimeString())
}
}, 1);
Like I want to execute the interval on two different devices and they should run in the exact same second or even ms if possible.
There's no guarantee that you can do this, not least because the JavaScript thread on one of the devices may be busy doing something else at that precise moment (it could even be tied up for several seconds).
Other than that, there's the issue of synchronizing the devices. Options are:
Some kind of synchronization event you send simultaneously to both devices. You'd run your code in response to the synchronization event received from your server. This is naturally subject to network delays, it requires a server to send the event (probably over web sockets), and is subject to the above caveat about the JavaScript thread being busy.
Relying on the devices being synced to exactly the same time source (for instance, perhaps they're both using a NIST time server or similar). If you know their times are synchronized sufficiently for your purposes, you can schedule your timer to fire at a precise moment, like this:
// Fire at exactly 14:30 GMT on 2021-04-21
const target = new Date(Date.UTC(2021, 3, 21, 14, 30)); // 3 = April, starts with 0 = Jan
const delay = Date.now() - target;
if (delay < 0) {
// It's already later than that
} else {
setTimeout(() => {
// Your code here
}, delay);
}
BUT, again, if the JavaScript thread is busy at that precise moment, the timer callback will run later, when the thread is free.
The code above schedules a single event, but if you need a recurring one, you can do the same basic logic: Determine the date/time you want the next callback to occur, find out how many milliseconds it is between now and then (Date.now() - target), and schedule the callback for that many milliseconds later.

Countdown timer with remote server - React native

I have an app that requires countdown timer. Due date comes from my back-end with rest api. I need to coundown remaining time in my react native app. But I can't use smart phone's time. Because user can be in different timezone / country etc. How i can use server's due date response for react native?
Should I send also remaining time in seconds to user? So I can countdown that remaining time every second?
https://www.example.com/getDueDate [POST]
returns:
Y-m-d H:i:s (future) time like 2021-05-20 23:40:40
If I use classic countdown approach for javascript, I need to use smart phone's time. But I don't want to use that.
NTP server approach can be tricky for react-native side. It just simple counter.
Why not send both the server's current time and the due date? Then start your timer from there?
That being said, the time will still be off by the roundtrip time between your user and the server (which will depend on their internet connection and your server's response time).
Yes, it is possible to get time. I'm also using rest api (token base authentication and expiry token after certain time). I'm checking as given below
var l_currentDateTimeSeconds;
l_currentDateTimeSeconds=((new Date().getTime() - "your_time_from_api") / 1000);
if (parseInt(l_CurrentDateTimeSeconds) < parseInt(your_time_from_api))
{
//failure case ;
}
else
{
//Success case;
}
output of time (in variable) will be in seconds. Visit given below link, it may be help
https://aboutreact.com/react-native-get-current-date-time/
This is the technique i use and it's really effective.
Step 1.
Send due date from server (5pm)
Send current time from server (4pm)
Step 2.
Check clients current time (3pm)
Subtract currentTime(server) - currentTime(client) and call it timeOffset
Step 3.
setInterval to run every second using the code example below.
//import useState, useEffect from react-native
const [timer,setTimer]=useState();
var serverExpiryDate="'the time the event will expire gotten from server";
var currentTimeAtServer="the time you got from server via api";
var currentTimeAtDevice=new Date().getTime();
const timeOffset= currentTimeAtServer - currentTimeAtDevice;
//timeOffset is the time difference between the user's clock and the server clock. Calculated when user received response from server.
useEffect(() => {
let interval = setInterval(() => {
setTimer(() => {
let endT = new Date(serverExpiryDate).getTime(); //time from server;
let nowT = new Date().getTime(); //current time on user've device
nowT = nowT + timeOffset; //VERY IMPORTANT, helps to sync user's time with server.
let remaining = endT >= nowT ? Math.floor((endT - nowT) / 1000) : 0;
let stopCheck = remaining === 0 ? clearInterval(interval) : null;
return remaining;
});
}, 1000); //each count lasts for a second
return () => {
clearInterval(interval);
};
}, []);
console.log(timer) //this will be decreasing every second

Building an alarm clock style application

I am building a webapp (referred to as the "noticeboard") for a friend's business, to aid with their packaging and dispatch operation. It is built using HTML, CSS & JS. The backend is built in PHP / MYSQL.
The noticeboard is for the benefit of their staff and displays dispatch cut-off ("event") times, i.e as follows:
Dispatch Time 1 : 09:00
Dispatch Time 2 : 11:30
Dispatch Time 3 : 14:30
Dispatch Time 4 : 16:00
They update these times on a regular basis, as their schedule depends on their delivery firm's schedule. There is an AJAX request running every 15 mins which simply fetches the latest times (JSON format) from the database and updates the noticeboard. Although I could just simply implement an "auto browser refresh" every 15 minutes, I found this was a bit inconsistent and sometimes a "page cannot be found" error message would be displayed.
The noticeboard also displays a real-time clock. I have built this using moment.js.
The system runs 24/7 in a Chrome browser running on Windows 10. Nothing else is running on the machine.
At the moment the noticeboard simply displays these times. I need to take this one step further and make it function almost like an alarm clock. What I'm basically looking to achieve is 15 minutes before each event, it needs to highlight the upcoming event time (i.e. using jQuery addClass()). Then as soon as that event time is reached, play a buzzer sound (some kind of MP3 file). This needs to happen automatically every day for every event. Remember the event times are always changing, so it would need to be smart enough to recognise this.
What techniques can I use to achieve this functionality? I have been reading up on things like setTimeout() and setInterval(), however I'm not sure these are able to "auto-update" themselves once they have been set (i.e. if an event time changes). Do I need to look at a nodeJs based solution? I don't have any experience in nodeJs but if that's the best way to achieve this then I'm willing to give it a go. Otherwise I'm more than happy to try out something in vanilla JS.
Here's how I would approach it using setTimeout() but obviously this doesn't dynamically update:
// set the number of ms to 15 mins before the event time
var eventInterval = 36000000;
// setTimeout function for the event
setTimeout(function() {
// add "active" class to highlight the event
$('.event').addClass('active');
// after 15 mins have elapsed, remove the "active" class
setTimeout(function() {
$('.event').removeClass('active');
}, 90000);
}, eventInterval;
Your approach is fine, however, you need to do that EVERY TIME you get an AJAX response. setTimeout returns a timeoutId, which then you can use for cancelling the timeout with clearTimeout(timeoutId).
var reminderTime = 15 * 60 * 1000;
var timeoutIds = [];
function setTime(timestamp) {
// Set the interval 15 minutes before the event time.
var interval = timestamp - reminderTime;
var timeoutId = setTimeout(function() {
// add "active" class to highlight the event
$('.event').addClass('active');
// after 15 mins have elapsed, remove the "active" class
setTimeout(function() {
$('.event').removeClass('active');
}, 90000);
}, interval);
timeoutIds.push(timeoutId);
}
$.get("http://myserver/getTimes", function(times) {
// Reset all the setTimeouts
timeoutIds.forEach(function(timeoutId) {
clearTimeout(timeoutId);
});
// Assuming times is an array of timestamps
times.forEach(setTime);
});

Why does setInterval not increment my clock properly in JavaScript?

I want to display the actual time in New York. I have a html div:
<div id="time"></div>
and also - I have a php script that returns the actual time:
<?php
date_default_timezone_set('UTC');
echo time();
?>
and it does it as a timestamp.
Now, I've created a js script:
var serverTime;
moment.tz.add('America/New_York|EST EDT|50 40|0101|1Lz50 1zb0 Op0');
function fetchTimeFromServer() {
$.ajax({
type: 'GET',
url: 'generalTime.php',
complete: function(resp){
serverTime = resp.responseText;
function updateTimeBasedOnServer(timestamp) { // Take in input the timestamp
var calculatedTime = moment(timestamp).tz("America/New_York");
var dateString = calculatedTime.format('h:mm:ss A');
$('#time').html(dateString + ", ");
};
var timestamp = serverTime*1000;
updateTimeBasedOnServer(timestamp);
setInterval(function () {
timestamp += 1000; // Increment the timestamp at every call.
updateTimeBasedOnServer(timestamp);
}, 1000);
}
})
};
fetchTimeFromServer();
setInterval(function(){
fetchTimeFromServer();
}, 5000);
and the idea behind it is that I want to fetch the data from server, display it on my webpage, then increment it every second for five seconds and then fetch the time from the server again (to keep consistence with time on the server). And later on - continue with doing so, fetching the time, incrementing it for 5 seconds, fetching it again, etc.
It works... almost. After the webpage stays open for some time I can see the actual time, but it 'blinks', and I can see that it shows different times - it's hard to explain, but it looks like there is some time already in that div and new time tries to overlay it for each second. Seems like the previous time (content of this div) is not removed... I don't know how to create a jsfiddle with a call to remote server to fetch time from php, so I only have this information pasted above :(
What might be the problem here?
Since javascript is single threaded, setInterval may not acutally run your function after the delay. It adds the function to the stack to be run as soon as the processor is ready for it. If the processor has other events in the stack, it will take longer than the interval period to run. Multiple intervals or timeouts are all adding calls to the same stack for processing. To address this, you could use HTML5 web workers or try using setTimeout recursively.
Here is a good read on web workers: https://msdn.microsoft.com/en-us/hh549259.aspx

How to have a timer which cannot be modified in javascript?

Basically, I am designing a quiz application with limited time. Use selects answer to a question and the next question loads using an Ajax request. All questions must be answered within a time frame of, say 2 minutes.
A clock ticks away to show how much time is left and as soon as it hits 0, results are shown. Now since the timer will be implemented using window.setTimeout(), it is possible that the value of timer variable be modified using an external bookmarklet or something like that. Anyway I can prevent this? I think this is implemented on file sharing sites like megaupload. Any forgery on the timer variable results in request for file being rejected.
Have .setTimeout() call an AJAX method on your server to synch time. Don't rely on the client time. You could also store the start time on the server for a quiz, and then check the end time when the quiz is posted.
You need to add a validation in your server side. When the client want to load the next question using an Ajax request, check whether deadline arrived.
The timer in client side js just a presention layer.
If the function runs as a immediately called function expression, then there are no global variables and nothing for a local script to subvert. Of course there's nothing to stop a user from reading your code and formulating a spoof, but anything to do with javascript is open to such attacks.
As others have said, use the server to validate requests based on the clock, do not rely on it to guarantee anything. Here's a simple count down that works from a start time so attempts to dealy execution won't work. There are no global variables to reset or modify either.
e.g.
(function (){
// Place to write count down
var el = document.getElementById('secondsLeft');
var starttime,
timeout,
limit = 20; // Timelimit in seconds
// Function to run about every second
function nextTick() {
var d = new Date();
// Set start time the first time
if (!starttime) starttime = d.getTime();
var diff = d.getTime() - starttime;
// Only run for period
if (diff < (limit * 1000)) {
el.innerHTML = limit - (diff/1000 | 0);
} else {
// Time's up
el.innerHTML = 0;
clearTimeout(timeout);
}
}
// Kick it off
timeout = window.setInterval(nextTick, 1000);
}());

Categories

Resources