Logging rainfall with Python - python

First post and I am at a dead end with this problem.
(some background)
I have a raspberry PiZero which I am developing a weather station with, so far it logs temp, humidity and pressure as well as sending the data to the windy.com API. Recently I added a tipping bucket rain gauge.
This has 2 wires which connect to the GPIO, when the bucket tips it momentarily competes the circuit, essentially a button press!
The goal here is to count the tips every hour, then reset. before resetting, send this data to log file + Windy API. This is the part I am struggling with.
I am pretty good with python but I am at a true writers block moment, here is a small program I cobbled together from snippets which counts the tips for testing
/usr/bin/python3
import requests
from gpiozero import Button
import time
rain_sensor = Button(27)
bucket_size = 0.2794
count = 0
def bucket_tipped():
global count
count = count + 1
print(count * bucket_size)
def reset_rainfall():
global count
count = 0
#display and log results
def timed_loop():
reset_rainfall
timeout = time.monotonic() + 3600 # 1 hour from now
while True:
if time.monotonic() > timeout: # break if timeout time is reached
rain_sensor.when_pressed = bucket_tipped
time.sleep(1) # Short sleep so loop can be interupted
continue
print count
# close the log file and exit nicely
GPIO.cleanup()

It looks like you are continuously setting your rain to 0 in your while True: loop.
Edit:
Try something like this for your loop.
def timed_loop():
rain = 0
timeout = time.monotonic() + 3600 # 1 hour from now
while True:
if time.monotonic() > timeout: # break if timeout time is reached
# You place your code here that you want to run every hour.
# After that the loop restarts
rain = 1
time.sleep(1) # Short sleep so loop can be interupted
continue
Edit 3:
With the following code you can record button presses over a specified amount of time.
import time
def bucket_tip_counter():
recording_time_timeout = 3600 # Amount of seconds you want to have the timer run
recording_time = time.monotonic() + recording_time_timeout
button_timeout = 1 # This timeout is here so the button doesnt trigger the count more then once for each trigger
# You have to modify this to your needs. If the button stays activated for a few seconds you need to set the timer accordingly.
count = 0 # Sets the counter to 0 at the start
button = 0 # Here you need to replace the 0 with the GPIO pin that returns True if the button is pressed
while True: # starts the loop
if button: # if button gets pressed/bucket tipped
count += 1 # up count by one
time.sleep(button_timeout) # wait specified timeout to make sure button isnt pressed anymore
if time.monotonic() > recording_time: # If the recording_time is reached the loop triggers this if condition
print(count) # print count
# Here you can also place code that you want to run when the hour is over
# Note that the counter wont start back up until that code is finished.
count = 0 # set count back to 0
recording_time = time.monotonic() + recording_time_timeout # Set a new timer so the hour can start anew
continue # restart the loop
time.sleep(1) # small sleep to stop CPU hogging.

Related

Why my thread doesn't stop after function finished?

So I wrote this script, which counts income packets on certain port, and in case if there are to many packets script has to do something. On the first received packet is has to start timer, and if timer reaches 60 sec, packet count should start from 0 again. It works, but only for first timer call, in any case, if script has to start timer again I get the error:
raise RuntimeError("threads can only be started once")
RuntimeError: threads can only be started once"`
It's clear, that this thread still running, but i don't understand why. I mean, in case if timer reaches 60 secs, timer loop is finished, and function should be finished too, so i can use timer again? Clearly i don't understand something here, can you guys explain it? Thanks for answers
My code:
from scapy.all import *
from threading import Thread
import time
global count
count = 0
def timer():
global count
i = 0
while i < 60:
if count > 0:
time.sleep(1)
i = i + 1
print(str(count))
else:
print("count is 0, timer turning off...")
break
else:
count = 0
print("60 seconds, timer is off")
background_thread = Thread(target=timer)
def pkt_callback(pkt):
global count
packet_limit = 10
if pkt.haslayer(UDP) and pkt.getlayer(UDP).dport == 5160 and pkt.haslayer(Raw):
raw = pkt.getlayer(Raw).load
s = str(raw)
if 'REGISTER' in s:
count += 1
print(count)
if count == 1:
if background_thread.is_alive() is False:
background_thread.start()
print("Register packet detected, timer is on")
if count >= packet_limit:
print("PACKETLIMIT reached, do smth")
count = 0
sniff(iface='ens160', filter="", prn=pkt_callback)
I think you have to use the return function not break, and either way you have only used it once, also you can change your code a bit, try this:
def timer():
global count
i = 0
while i < 60:
if count != 0:
time.sleep(1)
i += 1
print(str(count))
else:
return "count is 0, timer turning off..."
else:
count = 0
return "60 seconds, timer is off"

Python: How to take control of the cursor if cursor is inactive for five minutes and pause the program (my python program) if user touches the mouse?

I want to write a bot that will simulate mouse movements when user is away for more than 5 minutes and stay put when user takes control i.e. moves the mouse.
I have written following code as a part of the program.
Here is the link to my old program which clicks at given points periodically. The problem with this program is I have to start the program when I want to go somewhere and after returning close the program in order to resume working.
Here is the one of the module I wrote for the new program which detects whether mouse is moving or not.
import win32api
from time import sleep
print("starting engine.")
count = 0
while(True):
savedpos = win32api.GetCursorPos()
if count>20*5:
break
sleep(1)
curpos = win32api.GetCursorPos()
if savedpos == curpos:
savedpos = curpos
print("Mouse is steady.")
else:
print("Mouse is moving.")
count += 1
I wont be writing the code but I have the Idea to solve the problem
you use pyautogui.position() to keep checking the position and if it doesnt change position for 300 seconds you move it
I wrote following code referring other Stackoverflow posts.
This code waits 4 minutes for mouse being steady. Whenever mouse is moved, timer is reset to zero.
import win32api
from time import sleep
import pyautogui as gui
print("starting engine.")
count = 0
savedpos = win32api.GetCursorPos()
def actions():
print(gui.size())
while True:
#toast.show_toast("ROBOT V2 !", "Robot is active.", threaded=False, icon_path=None, duration=2)
gui.click()
gui.press('home')
gui.moveTo(541, 142, 0.25) # Money Transfer dropdown
gui.click()
sleep(0.5)
gui.moveTo(541, 172, 0.25) # Money Transfer link
gui.click()
sleep(5)
cond()
def cond():
count = 0
while True:
savedpos = win32api.GetCursorPos()
sleep(0.5)
curpos = win32api.GetCursorPos()
if savedpos == curpos:
savedpos = curpos
print("Mouse is steady. Elapsed time: ", (count+1)/2, " seconds.")
count += 1
if count >= 480: # if count is greater than 60 it means timeout will occur after mouse is steady for more than
# 240 seconds i.e. 4 minutes. (approx.)
print("User away for more than 4 minutes, taking control of the system.")
actions()
break
else:
pass
else:
print("Mouse is moving.")
count = 0
cond()

I am trying to execute an alarm function in tkinter but it is not working properly

I am trying to Execute the function in tkinter as I want function to run in background I have done following code. Also I am trying to execute it inside a while loop but its not looping through.
t1 = dt.time(hour = 13, minute= 24)
t2 = dt.time(hour= 13, minute= 4)
timetable = [t1, t2]
root = Tk()
def Alarm():
current_time = now_time.strftime("%H:%M:%S")
print(current_time)
print(timetable[0])
while True:
if timetable[0] <= dt.datetime.now().time():
print("Its time")
break
Alarm()
root.mainloop()
print statements are only for testing. The logic I am using in alarm clock is also not executing properly as it tells ""Its time" even after time has passed. I have tried following methods before.
method 1:
for i in reversed(timetable):
i_time = i
#print (i_time)
#print(now_time.strftime("%H:%M"))
while True:
if dt.datetime.now().time() < i_time:
#if i_time <= dt.datetime.now().time():
print("Its Time")
break
method 2:
for i in timetable:
current_time = dt.datetime.now().time()
alarm_time = i
while True:
if current_time < alarm_time:
if current_time <= alarm_time:
print("its time", alarm_time)
Using for loop was my first goal but for loop isn't executing properly. It only gets 1st element and doesn't go to 2nd element even if first element has passed so I have decided to go with if,elif,else statement
You can use the after method to run a function after a certain amount of time has elapsed. You should use it rather than creating a loop.
You simply need to convert the alarm time to a number of milliseconds, then use that to ring the alarm at the given time. For example, to ring an alarm in one hour you would do this:
def ring_alarm():
print("Its time")
delay = 60 * 60 * 1000 # 60 min/hour, 60 secs/min, 1000ms/sec
root.after(delay, ring_alarm)
I am going with if..else response for executing alarm as
current_time = dt.datetime.now().time()
if timetable[0] == current_time:
print("Its time")
break
I was breaking While loop in wrong place as well an typo from my end.

Pygame + python: 1 part of code has pygame.wait while rest of code runs

I am making a game in which u have to carry move objects from one place to another. I can move my character to the zone in which I need to put something. I want the player to wait in the zone for 5 secs before the object is placed there, however, if i do this you cannot move anymore if u decide u dont want to place the object in the zone as the whole script would be paused.
Is there a way to make one part of the script wait while the rest of it runs?
Every game needs one clock to keep the game loop in sync and to control timing. Pygame has a pygame.time.Clock object with a tick() method. Here's what a game loop could look like to get the behaviour you want (not complete code, just an example).
clock = pygame.time.Clock()
wait_time = 0
have_visited_zone = False
waiting_for_block_placement = False
# Game loop.
while True:
# Get the time (in milliseconds) since last loop (and lock framerate at 60 FPS).
dt = clock.tick(60)
# Move the player.
player.position += player.velocity * dt
# Player enters the zone for the first time.
if player.rect.colliderect(zone.rect) and not have_visited_zone:
have_visited_zone = True # Remember to set this to True!
waiting_for_block_placement = True # We're now waiting.
wait_time = 5000 # We'll wait 5000 milliseconds.
# Check if we're currently waiting for the block-placing action.
if waiting_for_block_placement:
wait_time -= dt # Decrease the time if we're waiting.
if wait_time <= 0: # If the time has gone to 0 (or past 0)
waiting_for_block_placement = False # stop waiting
place_block() # and place the block.
Example with threading:
from threading import Thread
def threaded_function(arg):
# check if it's been 5 seconds or user has left
thread = Thread(target = threaded_function, args = (10, ))
if user is in zone:
thread.start()
# continue normal code
Another potential solution is to check the time the user went into the zone and continuously check the current time to see if it's been 5 seconds
Time check example:
import time
entered = false
while true:
if user has entered zone:
entered_time = time.time()
entered = true
if entered and time.time() - entered_time >= 5: # i believe time.time() is in seconds not milliseconds
# it has been 5 seconds
if user has left:
entered=false
#other game code

Timer with Audio release

I created a timer with a specific condition, when it runs out, it should release an Audio.
My Input :
import time
import playsound
run = raw_input("Start? > ")
mins = 0
# Only run if the user types in "start"
if run == "start":
# Loop until we reach 2 minutes running
while mins != 2:
print ">>>>>>>>>>>>>>>>>>>>>", mins
if mins ==2:
playsound.playsound('C:\Audio.mp3', True)
time.sleep(60)
# Increment the minute total
mins += 1
But sadly it doesn't release anything
Would it not be easier to use the time.sleep() function that you are already using in your script to play the sound after two minutes?
Something like the below:
import time
import playsound
time.sleep(120)
playsound.playsound("C:\Audio.mp3", True)

Categories

Resources