From bafa6790ecef8a0eaff58c185206d84f2fed7b50 Mon Sep 17 00:00:00 2001 From: Natalie Albers Date: Tue, 18 Mar 2025 15:13:18 +0100 Subject: [PATCH 1/2] Add singleton protection to prevent read issues with multiple instantiations --- sense_hat/sense_hat.py | 14 +++++++++++++- tests/test_singleton.py | 12 ++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 tests/test_singleton.py diff --git a/sense_hat/sense_hat.py b/sense_hat/sense_hat.py index a639dc6..9e051e5 100644 --- a/sense_hat/sense_hat.py +++ b/sense_hat/sense_hat.py @@ -12,6 +12,7 @@ import pwd import array import fcntl +import threading from PIL import Image # pillow from copy import deepcopy @@ -20,7 +21,10 @@ from .exceptions import ColourSensorInitialisationError class SenseHat(object): - + # singleton registration variables + _instance = None + _lock = threading.Lock() + SENSE_HAT_FB_NAME = 'RPi-Sense FB' SENSE_HAT_FB_FBIOGET_GAMMA = 61696 SENSE_HAT_FB_FBIOSET_GAMMA = 61697 @@ -30,6 +34,14 @@ class SenseHat(object): SENSE_HAT_FB_GAMMA_USER = 2 SETTINGS_HOME_PATH = '.config/sense_hat' + # Ensure that there is only a single SenseHat object running to prevent sensor read issues + def __new__(cls): + if cls._instance is None: + with cls._lock: + if not cls._instance: + cls._instance = super().__new__(cls) + return cls._instance + def __init__( self, imu_settings_file='RTIMULib', diff --git a/tests/test_singleton.py b/tests/test_singleton.py new file mode 100644 index 0000000..755bb1a --- /dev/null +++ b/tests/test_singleton.py @@ -0,0 +1,12 @@ +from sense_hat import SenseHat +import unittest + + +class TestSingleton(unittest.TestCase): + def test_singleton(self): + sense1 = SenseHat() + sense2 = SenseHat() + self.assertEqual(sense1.temperature, sense2.temperature) + +if __name__ == "__main__": + unittest.main() \ No newline at end of file From ff2a781490591dee224344dd2a15327cf0914a36 Mon Sep 17 00:00:00 2001 From: Natalie Albers Date: Wed, 19 Mar 2025 16:14:30 +0100 Subject: [PATCH 2/2] Add test to demonstrate the single-instance nature of the sense object --- tests/test_singleton.py | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/tests/test_singleton.py b/tests/test_singleton.py index 755bb1a..22e6ea6 100644 --- a/tests/test_singleton.py +++ b/tests/test_singleton.py @@ -1,12 +1,33 @@ from sense_hat import SenseHat import unittest +import time +import concurrent.futures +def get_temp(dummy): + sense = SenseHat() + time.sleep(5) + print(dummy) + return round(sense.get_temperature()) + class TestSingleton(unittest.TestCase): def test_singleton(self): sense1 = SenseHat() sense2 = SenseHat() - self.assertEqual(sense1.temperature, sense2.temperature) - + self.assertEqual(sense1.get_temperature(), sense2.get_temperature()) + self.assertEqual(sense1, sense2) + + @unittest.expectedFailure + def test_multiprocess(self): + executions = ["run1", "run2", "run3", "run4", "run5"] + prev_temp = None + with concurrent.futures.ProcessPoolExecutor() as executor: + for temp in executor.map(get_temp,executions): + if prev_temp: + print(prev_temp, temp) + self.assertEqual(temp, prev_temp) + prev_temp = temp + + if __name__ == "__main__": unittest.main() \ No newline at end of file