Domoticz lua motion sensor - lua

--this script will turn of the light at the second living room when there is x min no movement detected on the Motion Sensor.
--The script does run and it sometime works, like once or twice a day. but it has to work always, I can't figure out why it is not working.
t1 = os.time()
s = otherdevices_lastupdate['Motion']
year = string.sub(s, 1, 4)
month = string.sub(s, 6, 7)
day = string.sub(s, 9, 10)
hour = string.sub(s, 12, 13)
minutes = string.sub(s, 15, 16)
seconds = string.sub(s, 18, 19)
commandArray = {}
t2 = os.time{year=year, month=month, day=day, hour=hour, min=minutes, sec=seconds}
difference = (os.difftime (t1, t2))
print(difference)
if (otherdevices['Motion'] == 'On' and difference > 60 and difference < 200) then
commandArray['Light']= 'Off'
print('2 minutes no movement, turn off Light 2th Living Room')
end
return commandArray

If the script runs successfully but it doesn't turn the light off even if it's expected to do so, then there are not many possible reasons.
Either otherdevices['Motion'] is not 'On' (the check is case sensitive) or the difference is out of the expected range of 60..200 seconds.

Solution #1:
...
if (otherdevices['Light']=='On' and otherdevices['Motion']~='On' and difference > 120) then
CommandArray['Light']='Off'
}
Solution #2 (better):
configure the Motion device so it activates the Light for 120 seconds, so it will be turned off automatically when Motion sensor stops toggling.

Related

How to update text on a loop in Lua/Solar2d

I'm trying to make a part of a program that's a timer through two loops. The timer will repeat a certain number of times (the it variable) hence the first loop. The second loop is the actual timer. For a certain number of seconds, every second it updates the text of a text object. The problem I face is that when I print the text of the text object to the console, it updates, but the text won't change on the screen itself until all the loops are done. Any help with explanation or anything to help guide me in the right direction would be very much appreciated.
Here is the code, don't worry about the unused parameters:
local function sleep(s)
local ntime = os.clock() + s/10
repeat until os.clock() > ntime
end
local function watch(mode, it, text, texty, para)
local text = display.newText(scene.view, "",
display.contentCenterX, 200, nativeSystemFont, 60)
text:setFillColor(0,0,256)
local i = 0
local sec = 0
local goal = 20
text.text = sec
while (i < it) do
sec = 0
while (sec < goal) do
sec = sec + 1
print(text.text)
text.text = sec
sleep(10)
end
i = i + 1
end
end

ipairs loop always returning just one of the values in lua?

Quick edit: _G.i is the 1 - 24 table I set to create a 24 hour time frame. It's globally stored in a tertiary script and implemented like this:
_G.i = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24}
So I'm trying to get this loop to work with a day/night cycle I have created. I want the loop to constantly check what time it is and print that time to the console based on a few parameters I set.
light = script.Parent.lightPart.lightCone
timeofday = ""
wait(1)
function checkTime()
for i, v in ipairs(_G.i) do
wait(1)
print(v)
print(timeofday)
if v > 20 and v < 6 then
timeofday = "night"
else
timeofday = "day"
end
end
end
while true do
checkTime()
wait(1)
end
For some reason, this is only printing day in the console even though I have it looping properly. The times are matched with the same of those in the day-night script. I'll post that here as well.
function changeTime()
for i, v in ipairs(_G.i) do
game.Lighting:SetMinutesAfterMidnight(v * 60)
wait(1)
end
end
while true do
changeTime()
end
Sorry if this post is sloppy or the code is sloppy I'm new to both. Have been trying to figure this out on my own, and been doing good on it originally I had no clue what a ipairs loops was but I managed to get it working with the day night cycle instead of a infinite wait(1) loop.
Your issue is the line:
if v > 20 and v < 6 then
v can never be both greater than 20 and less than 6. You need the or logical operator.
Beyond that, I'm not sure why you are using the global i to hold a list of the numbers 1 through 24? You can achieve the same affect with a ranging for loop. Also, if you are trying to check the current time set by your lower code, then you should store the time value in a global variable. Like so:
light = script.Parent.lightPart.lightCone
current_time = 0
function checkTime()
print(current_time)
if current_time > 20 or current_time < 6 then
timeofday = "night"
else
timeofday = "day"
end
print(timeofday)
end
while true do
checkTime()
wait(0.1)
end
function changeTime()
for v = 1, 24 do
game.Lighting:SetMinutesAfterMidnight(v * 60)
current_time = v
end
end
while true do
changeTime()
wait(1)
end
The issue with the way you were doing it is that you assume that the checkTime() function will always run after the changeTime() function, which is not necessarily the case.

Count time within time range

I need to count amount of time in specified range. For example, I have range (let's call it peak hours) 12:00-14:00. And i have another range(visit time), that might change, for ex 9:00-15:00. How do I get intersected hours for these 2 ranges?
As result I would like to get something like: {peak_hours: 2, regular_hours: 4}
Here peak_hours value is 2 as that many peak hours overlap with regular hours. And, regular_hours value is 4 as that many regular hours do not overlap with peak hours.
I'm kinda stuck with solution. I tried to use time ranges, but that didn't work for me. This is the code
peak_hours_range = Time.parse(peak_hour_start)..Time.parse(peak_hour_end)
session_range = visit_start..visit_end
inters = session_range.to_a & peak_hours_range.to_a
But this throws me type error
Here is one way to do it, we find the total hours in both ranges included, and then remove the peak hours from it to get effective regular hours.
require "time"
peak_hour_start = "12:00"
peak_hour_end = "14:00"
regular_hour_start = "9:00"
regular_hour_end = "15:00"
ph = (Time.parse(peak_hour_start).hour...Time.parse(peak_hour_end).hour).to_a
#=> [12, 13]
rh = (Time.parse(regular_hour_start).hour...Time.parse(regular_hour_end).hour).to_a
#=> [9, 10, 11, 12, 13, 14]
total = (ph + rh).uniq
#=> [12, 13, 9, 10, 11, 14]
r = {peak_hours: (ph - rh).size, regular_hours: (total - ph).size}
#=> {:peak_hours=>2, :regular_hours=>4}
You can always try to find the intersection yourself.
inters = nil
intersection_min = [peak_hour_start, visit_start].max
intersection_max = [peak_hour_end, visit_end].min
if intersection_min < intersection_max
inters = [intersection_min, intersection_max]
end
inters
Of course this can be cleaned up by extracting it out into it's own method.

I made a score counter but it is late [duplicate]

I am using timer.performWithDelay to time how long it takes a player to complete a level. I want it to measure down to the 100th of a second (because the game is multiplayer, and I don't want there to be too many ties).
Here is what I did:
local totaltime = 0
local function counter()
totaltime = totaltime + 0.01
print(totaltime)
end
timer1 = timer.performWithDelay( 10, counter, 0)
It results in each "second" lasting about 4 seconds. Is this just not practical or is there a flaw somewhere?
When timer.preformWithDelay is given a time delay smaller then the time between your frames the timer will wait until the next frame is entered to call the function.
That means if you have a game running at 30 or 60 fps, you would have a 'frame ms' of about 16 or 33ms. So the minimum delay you can put is the delay between your frames.
In your case you want to set your timer every 1/100th of a second, or with 10ms. This means, since your frame is most likely 16ms (60fps), that every logged 10ms you are actually waiting an addional 6ms.
Now you could solve this if you ran with 100 FPS and thus achieved said 10 ms, but this is NOT recommendable.
AlanPlantPot provided the answer for following solution on coronaLabs:
I would use the enterFrame function instead. Your timer won't go up in single milliseconds (it will increase by however many ms have passed in each frame), but nobody would be able to read that fast anyway.
local prevFrameTime, currentFrameTime --both nil
local deltaFrameTime = 0
local totalTime = 0
local txt_counter = display.newText( totalTime, 0, 0, native.systemFont, 50 )
txt_counter.x = 150
txt_counter.y = 288
txt_counter:setTextColor( 255, 255, 255 )
group:insert( txt_counter )
and
local function enterFrame(e)
local currentFrameTime = system.getTimer()
--if this is still nil, then it is the first frame
--so no need to perform calculation
if prevFrameTime then
--calculate how many milliseconds since last frame
deltaFrameTime = currentFrameTime - prevFrameTime
end
prevFrameTime = currentFrameTime
--this is the total time in milliseconds
totalTime = totalTime + deltaFrameTime
--multiply by 0.001 to get time in seconds
txt_counter.text = totalTime * 0.001
end

CoronaSDK - Implementing game timer counting milliseconds

I am using timer.performWithDelay to time how long it takes a player to complete a level. I want it to measure down to the 100th of a second (because the game is multiplayer, and I don't want there to be too many ties).
Here is what I did:
local totaltime = 0
local function counter()
totaltime = totaltime + 0.01
print(totaltime)
end
timer1 = timer.performWithDelay( 10, counter, 0)
It results in each "second" lasting about 4 seconds. Is this just not practical or is there a flaw somewhere?
When timer.preformWithDelay is given a time delay smaller then the time between your frames the timer will wait until the next frame is entered to call the function.
That means if you have a game running at 30 or 60 fps, you would have a 'frame ms' of about 16 or 33ms. So the minimum delay you can put is the delay between your frames.
In your case you want to set your timer every 1/100th of a second, or with 10ms. This means, since your frame is most likely 16ms (60fps), that every logged 10ms you are actually waiting an addional 6ms.
Now you could solve this if you ran with 100 FPS and thus achieved said 10 ms, but this is NOT recommendable.
AlanPlantPot provided the answer for following solution on coronaLabs:
I would use the enterFrame function instead. Your timer won't go up in single milliseconds (it will increase by however many ms have passed in each frame), but nobody would be able to read that fast anyway.
local prevFrameTime, currentFrameTime --both nil
local deltaFrameTime = 0
local totalTime = 0
local txt_counter = display.newText( totalTime, 0, 0, native.systemFont, 50 )
txt_counter.x = 150
txt_counter.y = 288
txt_counter:setTextColor( 255, 255, 255 )
group:insert( txt_counter )
and
local function enterFrame(e)
local currentFrameTime = system.getTimer()
--if this is still nil, then it is the first frame
--so no need to perform calculation
if prevFrameTime then
--calculate how many milliseconds since last frame
deltaFrameTime = currentFrameTime - prevFrameTime
end
prevFrameTime = currentFrameTime
--this is the total time in milliseconds
totalTime = totalTime + deltaFrameTime
--multiply by 0.001 to get time in seconds
txt_counter.text = totalTime * 0.001
end

Resources