To me, this does not appear to be an issue with your use of globals, though I would discourage using globals, and instead make a class WindMonitor. You should also use a lock if you are accessing a variable from multiple threads.
Try this out (I had to call spin on random time intervals because I don't have gpios on my device).
wspeed.py
# from gpiozero import Button
import math
import random
import threading
from time import sleep
DEFAULT_WIND_SENSOR = None; # Button(6)
class WindMonitor:
def __init__(self, button=DEFAULT_WIND_SENSOR):
self.wind_count = 0
self.wind_list = []
self.button = button
self.wind_count_lock = threading.Lock()
def calculate_speed(self, stop_event):
while True:
with self.wind_count_lock:
print(self.wind_count)
radius_cm = 9.0
cm_in_mile = 160934.4
circumference_cm = (2 * math.pi) * radius_cm
rotations = self.wind_count / 2.0
dist_miles = (circumference_cm * rotations) / cm_in_mile
speed = dist_miles / 5 # Divide distance by time, 5 seconds
print(speed)
self.wind_list.append(speed)
self.wind_count = 0 # Reset wind count
if stop_event.wait(5):
return
def spin(self):
with self.wind_count_lock:
self.wind_count += 1
def monitor_wind(self):
# self.button.when_pressed = self.spin
while True:
sleep(float(random.randint(1, 10)) / 10)
self.spin()
__main__.py
import threading as th
import time
from wspeed import WindMonitor
if __name__ == '__main__':
monitor = WindMonitor()
stop_event = th.Event()
th_wmonitor = th.Thread(target=monitor.monitor_wind, daemon=True)
th_wspeed = th.Thread(target=monitor.calculate_speed, args=[stop_event], daemon=True)
try:
th_wspeed.start()
th_wmonitor.start()
while True: time.sleep(100)
except (KeyboardInterrupt, SystemExit):
stop_event.set()
Edit: Explaining stop event
All of your threads loop forever (main thread, th_wmonitor, and th_wspeed).
You want the program to exit when the main terminates.
When python exits, it waits for all non-daemonic threads to terminate, so you did the right thing by making them daemonic. The problem is that python will only exit when there is a single remaining daemonic thread. Because both daemonic threads loop infinitely, you need a way to tell one (or both) of them to when the program exits.
The simplest way of achieving this is to use a threading.Event object. An Event is a simple way of communicating between threads. It's basically a flag that you set in one thread and check in another. By having an exception in main, you can set the stop_event instance of threading.Event. This lets any thread with access to stop_event that the main thread has exited, and other threads may terminate when they are ready to terminate.
The th_wspeed needs to terminate at a specific time because you don't want to terminate in the middle of a print statement. For that reason, I made th_wspeed the one to check stop_event. When th_wspeed sees stop_event has been set, it returns, thus terminating one of the two daemonic threads. At that point, because python sees that only one daemonic thread remains, it will force that thread to terminate, and the program exits.
Without the stop event, the program would not terminate when you, for example, press CTRL+C.
monitor_wind? The simple explanation is thatspinisn't being called, which means that the callback is never being registered, or the callback isn't being called. Please show a minimal reproducible example.monitor_windand watchingwind_countincrement.from wspeed import monitor_wind, calculate_speed, wind_avg, wind_list th_wmonitor = th.Thread(target=monitor_wind, daemon=True) th_wspeed = th.Thread(target=calculate_speed, daemon=True) th_wspeed.start(); th_wmonitor.start()monitor_windlooks like it doesn't actually run thespinfunction, it just bindsspinto yourwind_sensorbutton. Is there a reason you don't just bind it once at the start? It looks like if you do that,spinis still run every time the button is pressed.calculate_speedifwind_countis not 0