Running multiple timers? - lua

I've got nodemcu and trying to achieve the following.
- Every 5 mins send data to a remote website.
- Every 1 second check sensors
So have 2 functions:
function checkSensors()
print("checking sensors")
-- do some stuff here
end
function sendData()
print("Sending Data")
-- do some stuff here
end
tmr.alarm(0, 1000, 1, function() checkSensors() end )
tmr.alarm(0, 300000, 1, function() sendData() end )
If I comment out the first tmr then every 5 mins secs the function sendData is called. Likewise commenting out the first tmr the function sendData is called every sec.
However with both in on sendData is called.
How can I use both timers, or is there another way I'm supposed to do this.

The first parameter to tmr.alarm is the ID of the timer. Because you use 0 for both calls, this simply reconfigures one timer twice. If you want multiple timers, you need to pass different IDs for each one.
There are 7 static timers (0-6), though these are going away. You can create dynamic timers with tmr.create. The returned ID can be passed to tmr.alarm.

Related

AudioKit AKPlayer stop with at AVAudioTime method

In AudioKit there is this method for AKPlayer:
#objc dynamic public func play(at audioTime: AVAudioTime?)
I want the same for stop method because I want to be able to stop the player at any time when the user hits the stop button. I am making a music app and I need to stop the sound in X time which is calculated based on BPM and etc.
Here is how I start my AKPlayer:
drums.play(at: AVAudioTime.now() + timeToClosestBeatGrid)
I want the same API with stop:
drums.stop(at: AVAudioTime.now() + timeToClosestBeatGrid) // this api doesnt exist :(((
I tried using endTime property by setting it but it does not seem to do anything...
How may I accomplish this?
PS: I am not looking for a Timer solution this is because a timer is not 100% accurate. I want my stop method to be 100% accurate just like play method
The most accurate way to schedule events in AudioKit is by using AKSequencer. The sequencer can be connected to a callback instrument, which is a node that passes the events to an user-defined function.
In your case, you would add an event at the time where you want the player to stop. In your callback function, you would stop the player as a response to that event.
This is an outline of what should be done:
Create a track to contain the stop event, using AKSequencer's addTrack method. Connect this track to an AKCallbackInstrument. Please see this answer on how to connect an AKCallbackInstrument to an AKSequencer track.
Add the stop event to the track, at the time position where you want the music to stop. As you will be interpreting the event yourself with a callback function, it doesn't really matter what type of event you use. You could simply use a Note On.
In the callback function, stop the player when that event is received.
This is what your callback function would look like:
func stopCallback(status:UInt8, note:MIDINoteNumber, vel:MIDIVelocity) -> () {
guard let status = AKMIDIStatus(byte: status),
let type = status.type,
type == .noteOn else { return }
drums.stop()
}
According to AudioKit documentation, you can try using the schedule(at:) method:
You can call this to schedule playback in the future or the player will call it when play() is called to load the audio data
After the play() method you should declare this schedule(at:) with an offset AVAudioTime.now() + timeToClosestBeatGrid and specify .dataPlayedBack as completion callback type, because this completion is called when (from docs)...
The buffer or file has finished playing
and now (in completion block) you can call drums.stop()
But... If the .stop() method should be called whenever the button is pressed, why not use some form of delay (Timer or DispatchQueue) with the value timeToClosestBeatGrid as the offset?

Sequence operations

I have a little card playing app. When the computer is playing, some functions are being fired after some time to mimic a real player, like so:
self.operation.addOperation {
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now()+2) {
self.passTurn()
}
}
Everything works fine, but when I want to cancel the game and start a new one, the app crashes if I do it within two seconds before the self.passTurn() function fires.
Ideally I would like to have some sort of pause between the different operations. The above mentioned operation gets released from the queue immediately after it fires the delayed function, so cancelling or suspends the operation does not work.
Is it possible to somehow retain the operation in the queue for two seconds and release it afterwards when the actual function is done?
Thanks!

Can I make Lua wait for an event to finish before executing again?

I am using events in Lua I subscribe with:
Runtime:addEventListener("balanceChanged", onBalanceChanged)
And raise them with
Runtime:dispatchEvent({ name = "balanceChanged" })
Now in onBalanceChanged, I want to do some animation on the screen that may take a few seconds to finish - but during this time the same event can be dispatched again.
How to I ensure that the onBalanceChanged function is only executed one at a time, aka if it's currently executing, wait for it to finish before carrying on?
ex:
local isAnimOver = false
function playAnimation()
if not isAnimover then
isAnimOver = true
-- here play the animation
--- Once the animation is over then set the flag to
isAnimOver = false
end
end

In Titanium, what's the difference between the pause event and registerBackgroundService in ios?

In a nutshell, what's the point of having Ti.App.iOS.registerBackgroundService when you can do a similar thing with attaching a function to the "pause" event? Are there any differences between the two approaches in Titanium?
e.g.
version 1:
app.js:
service = Ti.App.iOS.registerBackgroundService({
url:"bg.js"
});
bg.js:
var sec = 0;
setInterval(function(){console.log('counting' + sec); sec = sec + 1}, 1000);
Version 2:
app.js
Titanium.App.addEventListener('pause', function(){
var sec = 0;
setInterval(function(){console.log('counting' + sec); sec = sec + 1}, 1000);
});
Version 1 & Version 2 do the exact same thing (when the app is put in the background).
Version 1 and Version 2 are not doing the same thing. Background service is a service that runs when the application is placed in the background and it will stop automatically when the application returns from background. And it can invoke Titanium.App.iOS.LocalNotification.
pause is an event which is fired when the application transitions from active to inactive state on a multitasked system. This event fires when the user leaves the application or for certain types of temporary interruptions such as a notification or incoming phone call.
From Documentation,
Note that calls to functions that modify the UI during this event may
be partially executed, up to the UI call before the suspension. See
paused event. If this happens, the remainder of the code will be
executed after the application is resumed, but before the resume event
is triggered.
Both are different and doing different jobs

ytplayer api event when reaching a position in a video?

Is there a way to cause an event when a video reaches a specific time? I want to get to a callback function at the time when the video has reached to a certain time, and the time it takes for the video to reach that time is unpredictable, since the user can skip part of the video, or buffering might take some time before the video resumes, or something like that, so simply setting a timed event wont work because the video might reach specific time earlier.
I can query the time of the video, but what I want is to get a callback when the video has reached a certain time. Is there a way to do this?
I'm not going to write the full code, but you should set up an interval, like this:
var time = 70; // Time in seconds, e.g. this one is one minute and 10 seconds
var reached = false;
var interval = setInterval(function(){
if(player.getCurrentTime() >= time && !reached) {
clearInterval(interval);
reached = true;
timeReached();
}
},1000);
function timeReached() {
// Do what you have to
}
You can use this Javascript wrapper for the YouTube player API.
The API provides very simple event handling. E.g:
youtubePlayer.at('5000', function() {
alert("You're five seconds into this Youtube clip");
});
use player.getCurrentTime()!
https://developers.google.com/youtube/iframe_api_reference#Playback_status

Resources