diff --git a/docs/button_triggered_display.md b/docs/button_triggered_display.md new file mode 100644 index 0000000..f956ad3 --- /dev/null +++ b/docs/button_triggered_display.md @@ -0,0 +1,89 @@ +# Button-Triggered Sensor Display + +This document explains how to use the button-triggered sensor display example, which demonstrates an energy-efficient approach to reading and displaying sensor data on ESP32/ESP8266 devices. + +## Overview + +The button-triggered display example shows how to: + +1. Set up a button input on an ESP device +2. Use low-power sleep mode to conserve energy +3. Wake up and read sensor data when the button is pressed +4. Display the data on an OLED screen + +This approach is ideal for battery-powered applications where energy conservation is important. + +## Hardware Requirements + +- ESP32 or ESP8266 development board +- DHT22 temperature and humidity sensor +- SSD1306 OLED display (128x64 pixels recommended) +- Pushbutton +- 10K pull-up resistor (if your button doesn't have an internal pull-up) +- Breadboard and jumper wires + +## Wiring + +1. **DHT22 Sensor**: + - Connect VCC to 3.3V + - Connect GND to ground + - Connect DATA to GPIO4 (or change the pin in the code) + +2. **OLED Display**: + - Connect VCC to 3.3V + - Connect GND to ground + - Connect SCL to GPIO22 (or change the pin in the code) + - Connect SDA to GPIO21 (or change the pin in the code) + +3. **Button**: + - Connect one side to GPIO0 (or change the pin in the code) + - Connect the other side to ground + - Connect a 10K pull-up resistor between GPIO0 and 3.3V (if not using internal pull-up) + +## Running the Example + +1. Flash MicroPython to your ESP device if you haven't already +2. Upload the `button_triggered_display.py` script to your device +3. Run the script + +```python +import button_triggered_display +button_triggered_display.main() +``` + +## How It Works + +### Energy Conservation + +The example uses ESP32's light sleep mode to conserve energy when not actively reading or displaying data. In light sleep mode: + +- The CPU is paused +- RAM is preserved +- Peripherals can be configured to wake the device +- Power consumption is significantly reduced + +### Button Wake-Up + +The device is configured to wake up from sleep when the button is pressed. This is done using the `wake_on_ext0` function, which allows an external pin to trigger a wake-up event. + +### Simulation Mode + +The example includes a simulation mode that runs when not on actual ESP hardware. This allows you to test the functionality on a development computer before deploying to the ESP device. + +## Customization + +You can customize the example by: + +1. Changing the GPIO pins for the sensor, display, or button +2. Adjusting the display time before going back to sleep +3. Adding additional sensors +4. Modifying the information displayed on the OLED screen + +## Power Consumption + +Typical power consumption in different states: + +- Active mode (reading sensors and updating display): ~80-120mA +- Light sleep mode: ~0.8-1.5mA + +This represents a power saving of approximately 98% during idle periods, significantly extending battery life. \ No newline at end of file diff --git a/docs/oled_display.md b/docs/oled_display.md new file mode 100644 index 0000000..e1c1259 --- /dev/null +++ b/docs/oled_display.md @@ -0,0 +1,165 @@ +# OLED Display Module + +This module provides a class for interfacing with SSD1306 OLED displays via I2C on ESP32/ESP8266 microcontrollers. + +## Features + +- Compatible with SSD1306 OLED displays +- I2C interface support +- Display text at specific coordinates +- Display a list of values (e.g., sensor readings) +- Simulation mode for testing without hardware +- Integration with the ESP Sensors framework + +## Hardware Requirements + +- ESP32 or ESP8266 microcontroller +- SSD1306 OLED display (common sizes: 128x64, 128x32, 64x48) +- I2C connection (2 pins: SCL and SDA) + +## Installation + +The OLED display module is part of the ESP Sensors package. No additional installation is required if you have already installed the package. + +## Usage + +### Basic Initialization + +```python +from esp_sensors.oled_display import OLEDDisplay + +# Initialize the display +display = OLEDDisplay( + name="Status Display", + scl_pin=22, # GPIO pin for I2C clock + sda_pin=21, # GPIO pin for I2C data + width=128, # Display width in pixels + height=64, # Display height in pixels + address=0x3C # I2C address (default: 0x3C) +) +``` + +### Displaying Text + +```python +# Clear the display +display.clear() + +# Display text at specific coordinates +display.display_text("Hello, World!", x=0, y=0) +display.display_text("Line 2", x=0, y=10) +display.display_text("ESP32", x=64, y=30) +``` + +### Displaying Multiple Values + +```python +# Display a list of values (e.g., sensor readings) +display.display_values([ + "Temperature: 25.5°C", + "Humidity: 45%", + "Pressure: 1013 hPa", + "Time: 12:34:56" +]) +``` + +### Integration with Sensors + +```python +from esp_sensors.dht22 import DHT22Sensor + +# Initialize a DHT22 sensor +sensor = DHT22Sensor("Living Room", pin=4) + +# Read sensor values +temperature = sensor.read_temperature() +humidity = sensor.read_humidity() + +# Display sensor values +display.display_values([ + f"Temp: {temperature:.1f}°C", + f"Humidity: {humidity:.1f}%" +]) +``` + +## API Reference + +### Class: OLEDDisplay + +#### Constructor + +```python +OLEDDisplay(name, scl_pin, sda_pin, width=128, height=64, address=0x3C, interval=60) +``` + +Parameters: +- `name` (str): The name of the display +- `scl_pin` (int): The GPIO pin number for the SCL (clock) line +- `sda_pin` (int): The GPIO pin number for the SDA (data) line +- `width` (int): Display width in pixels (default: 128) +- `height` (int): Display height in pixels (default: 64) +- `address` (int): I2C address of the display (default: 0x3C) +- `interval` (int): Refresh interval in seconds (default: 60) + +#### Methods + +##### clear() + +Clears the display. + +```python +display.clear() +``` + +##### display_text(text, x=0, y=0, color=1) + +Displays text at the specified position. + +Parameters: +- `text` (str): The text to display +- `x` (int): X coordinate (default: 0) +- `y` (int): Y coordinate (default: 0) +- `color` (int): Pixel color (1 for white, 0 for black, default: 1) + +```python +display.display_text("Hello", x=10, y=20) +``` + +##### display_values(values) + +Displays a list of values on the OLED screen. + +Parameters: +- `values` (list): List of values to display (strings or objects with __str__ method) + +```python +display.display_values(["Line 1", "Line 2", "Line 3"]) +``` + +##### get_metadata() + +Returns a dictionary containing display metadata. + +```python +metadata = display.get_metadata() +print(metadata) +``` + +## Troubleshooting + +### Display Not Working + +1. Check the I2C address (common addresses are 0x3C and 0x3D) +2. Verify the SCL and SDA pin connections +3. Ensure the display is powered correctly (usually 3.3V) +4. Try a different I2C bus speed if available + +### Text Not Displaying Correctly + +1. Check that the coordinates are within the display dimensions +2. Ensure the text doesn't exceed the display width +3. Try using smaller font or breaking text into multiple lines + +## Example + +See the `examples/oled_display_example.py` file for a complete example of using the OLED display with sensors. \ No newline at end of file diff --git a/examples/button_triggered_display.py b/examples/button_triggered_display.py new file mode 100644 index 0000000..c450c31 --- /dev/null +++ b/examples/button_triggered_display.py @@ -0,0 +1,137 @@ +""" +Example of an energy-efficient sensor display that activates on button press. + +This example demonstrates how to: +1. Set up a button input +2. Use low-power sleep mode to conserve energy +3. Wake up and read sensor data when the button is pressed +4. Display the data on an OLED screen +""" +import time +import sys +import os + +# Add the src directory to the Python path +sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) + +from src.esp_sensors.oled_display import OLEDDisplay +from src.esp_sensors.dht22 import DHT22Sensor + +# Import hardware-specific modules if available (for ESP32/ESP8266) +try: + from machine import Pin, deepsleep + import esp32 + SIMULATION = False +except ImportError: + # Simulation mode for development on non-ESP hardware + SIMULATION = True + print("Running in simulation mode - hardware functions will be simulated") + + +def simulate_button_press(): + """Simulate a button press in simulation mode.""" + print("\nPress Enter to simulate a button press (or 'q' to quit, Ctrl+C to exit)...") + try: + user_input = input() + if user_input.lower() == 'q': + return False + return True + except KeyboardInterrupt: + return False + + +def main(): + """ + Main function to demonstrate button-triggered sensor display. + """ + # Initialize a DHT22 sensor + dht_sensor = DHT22Sensor( + name="Living Room", + pin=4, # GPIO pin for DHT22 data + interval=5, # Read every 5 seconds + unit="C" # Celsius + ) + + # Initialize an OLED display + display = OLEDDisplay( + name="Status Display", + scl_pin=22, # GPIO pin for I2C clock + sda_pin=21, # GPIO pin for I2C data + width=128, # Display width in pixels + height=64, # Display height in pixels + interval=1 # Update every second + ) + + # Set up button on GPIO pin 0 (common button pin on many ESP boards) + button_pin = 0 + if not SIMULATION: + button = Pin(button_pin, Pin.IN, Pin.PULL_UP) + + # Display initialization message + display.clear() + display.display_text("Ready - Press Button", 0, 0) + print("System initialized. Waiting for button press...") + + # Main loop - sleep until button press, then read and display sensor data + try: + while True: + # Wait for button press + if SIMULATION: + # In simulation mode, wait for Enter key + if not simulate_button_press(): + break # Exit if Ctrl+C was pressed + else: + # In hardware mode, check if button is pressed (active low) + if button.value() == 1: # Button not pressed + # Go to light sleep mode to save power + # Wake up on pin change (button press) + print("Entering light sleep mode...") + esp32.wake_on_ext0(pin=button, level=0) # Wake on button press (low) + esp32.light_sleep() # Light sleep preserves RAM but saves power + # When we get here, the button was pressed + + print("Button pressed! Reading sensor data...") + + # Read sensor values + temperature = dht_sensor.read_temperature() + humidity = dht_sensor.read_humidity() + + # Format values for display + temp_str = f"Temp: {temperature:.1f} C" + hum_str = f"Humidity: {humidity:.1f}%" + time_str = f"Time: {time.time():.0f}" + name_str = f"Sensor: {dht_sensor.name}" + + # Display values + display.display_values([ + name_str, + temp_str, + hum_str, + time_str, + "Press button again" + ]) + + # Print to console + print(f"Updated display with: {temp_str}, {hum_str}") + + # Keep display on for a few seconds before going back to sleep + time.sleep(5) + + # Clear display to save power + display.clear() + display.display_text("Ready - Press Button", 0, 0) + + if SIMULATION: + print("Display cleared. Ready for next button press.") + + except KeyboardInterrupt: + # Clean up on exit + display.clear() + display.display_text("Shutting down...", 0, 0) + time.sleep(1) + display.clear() + print("Program terminated by user") + + +if __name__ == "__main__": + main() diff --git a/examples/oled_display_example.py b/examples/oled_display_example.py new file mode 100644 index 0000000..3557fad --- /dev/null +++ b/examples/oled_display_example.py @@ -0,0 +1,84 @@ +""" +Example usage of the OLED display with temperature and humidity sensors. +""" +import time +import sys +import os + +# Add the src directory to the Python path +sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) + +from src.esp_sensors.oled_display import OLEDDisplay +from src.esp_sensors.dht22 import DHT22Sensor + + +def main(): + """ + Main function to demonstrate OLED display usage with sensors. + """ + # Initialize a DHT22 sensor + dht_sensor = DHT22Sensor( + name="Living Room", + pin=4, # GPIO pin for DHT22 data + interval=5, # Read every 5 seconds + unit="C" # Celsius + ) + + # Initialize an OLED display + display = OLEDDisplay( + name="Status Display", + scl_pin=22, # GPIO pin for I2C clock + sda_pin=21, # GPIO pin for I2C data + width=128, # Display width in pixels + height=64, # Display height in pixels + interval=1 # Update every second + ) + + # Display initialization message + display.clear() + display.display_text("Initializing...", 0, 0) + time.sleep(2) + + # Main loop - run for 5 iterations as a demonstration + try: + print("Starting demonstration (5 iterations)...") + for i in range(5): + print(f"\nIteration {i+1}/5:") + + # Read sensor values + temperature = dht_sensor.read_temperature() + humidity = dht_sensor.read_humidity() + + # Format values for display + temp_str = f"Temp: {temperature:.1f} C" + hum_str = f"Humidity: {humidity:.1f}%" + time_str = f"Time: {time.time():.0f}" + name_str = f"Sensor: {dht_sensor.name}" + + # Display values + display.display_values([ + name_str, + temp_str, + hum_str, + time_str, + f"Demo ({i+1}/5)" + ]) + + # Print to console in simulation mode + print(f"Updated display with: {temp_str}, {hum_str}") + + # Wait for next update + print(f"Waiting {display.interval} second(s)...") + time.sleep(display.interval) + + except KeyboardInterrupt: + # Clean up on exit + display.clear() + display.display_text("Shutting down...", 0, 0) + time.sleep(1) + display.clear() + print("Program terminated by user") + + +if __name__ == "__main__": + main() diff --git a/src/esp_sensors/dht22.py b/src/esp_sensors/dht22.py index 3021368..5e0d038 100644 --- a/src/esp_sensors/dht22.py +++ b/src/esp_sensors/dht22.py @@ -10,10 +10,11 @@ except ImportError: import random SIMULATION = True -from .sensor import Sensor +from .temperature import TemperatureSensor +from .humidity import HumiditySensor -class DHT22Sensor(Sensor): +class DHT22Sensor(TemperatureSensor, HumiditySensor): """DHT22 temperature and humidity sensor implementation.""" def __init__(self, name: str, pin: int, interval: int = 60, unit: str = "C"): @@ -26,17 +27,15 @@ class DHT22Sensor(Sensor): interval: Reading interval in seconds (default: 60) unit: Temperature unit, either "C" for Celsius or "F" for Fahrenheit (default: "C") """ - super().__init__(name, pin, interval) - if unit not in ["C", "F"]: - raise ValueError("Unit must be either 'C' or 'F'") - self.unit = unit - self._last_humidity = None + # Initialize both parent classes + TemperatureSensor.__init__(self, name, pin, interval, unit) + HumiditySensor.__init__(self, name, pin, interval) # Initialize the sensor if not in simulation mode if not SIMULATION: self._sensor = dht.DHT22(Pin(pin)) - def read(self) -> float: + def read_temperature(self) -> float: """ Read the current temperature. @@ -44,14 +43,11 @@ class DHT22Sensor(Sensor): The temperature reading as a float """ if SIMULATION: - # Simulate temperature reading - if self.unit == "C": - self._last_reading = round(random.uniform(15.0, 30.0), 1) - else: - self._last_reading = round(random.uniform(59.0, 86.0), 1) - - # Simulate humidity reading (between 30% and 90%) - self._last_humidity = round(random.uniform(30.0, 90.0), 1) + # Use parent class simulation for temperature + temp_reading = super().read_temperature() + # Also update humidity in simulation mode + self._last_humidity = super().read_humidity() + return temp_reading else: # Actual hardware reading try: @@ -63,6 +59,7 @@ class DHT22Sensor(Sensor): temp = (temp * 9 / 5) + 32 self._last_reading = round(temp, 1) + # Also read humidity while we're at it self._last_humidity = round(self._sensor.humidity(), 1) except Exception as e: print(f"Error reading DHT22 sensor: {e}") @@ -74,6 +71,15 @@ class DHT22Sensor(Sensor): return self._last_reading + def read(self) -> float: + """ + Read the current temperature (wrapper for read_temperature). + + Returns: + The temperature reading as a float + """ + return self.read_temperature() + def read_humidity(self) -> float: """ Read the current humidity. @@ -84,8 +90,8 @@ class DHT22Sensor(Sensor): # If we haven't read yet, read only humidity if self._last_humidity is None: if SIMULATION: - # Simulate humidity reading (between 30% and 90%) - self._last_humidity = round(random.uniform(30.0, 90.0), 1) + # Use parent class simulation + return super().read_humidity() else: # Actual hardware reading try: @@ -104,9 +110,13 @@ class DHT22Sensor(Sensor): Returns: A dictionary containing sensor metadata """ - metadata = super().get_metadata() - metadata["unit"] = self.unit - metadata["last_humidity"] = self._last_humidity + # Get metadata from TemperatureSensor + temp_metadata = TemperatureSensor.get_metadata(self) + # Get metadata from HumiditySensor + humidity_metadata = HumiditySensor.get_metadata(self) + + # Combine metadata from both parent classes + metadata = {**temp_metadata, **humidity_metadata} metadata["type"] = "DHT22" return metadata diff --git a/src/esp_sensors/humidity.py b/src/esp_sensors/humidity.py new file mode 100644 index 0000000..4d67874 --- /dev/null +++ b/src/esp_sensors/humidity.py @@ -0,0 +1,44 @@ +""" +Humidity sensor module for ESP-based sensors. +""" +import random +from .sensor import Sensor + + +class HumiditySensor(Sensor): + """Humidity sensor implementation.""" + + def __init__(self, name: str, pin: int, interval: int = 60): + """ + Initialize a new humidity sensor. + + Args: + name: The name of the sensor + pin: The GPIO pin number the sensor is connected to + interval: Reading interval in seconds (default: 60) + """ + super().__init__(name, pin, interval) + self._last_humidity = None + + def read_humidity(self) -> float: + """ + Read the current humidity. + + Returns: + The humidity reading as a float (percentage) + """ + # This is a simulation for testing purposes + # In a real implementation, this would read from the actual sensor + self._last_humidity = round(random.uniform(30.0, 90.0), 1) + return self._last_humidity + + def get_metadata(self): + """ + Get sensor metadata including humidity information. + + Returns: + A dictionary containing sensor metadata + """ + metadata = super().get_metadata() + metadata["last_humidity"] = self._last_humidity + return metadata \ No newline at end of file diff --git a/src/esp_sensors/oled_display.py b/src/esp_sensors/oled_display.py new file mode 100644 index 0000000..31bcd22 --- /dev/null +++ b/src/esp_sensors/oled_display.py @@ -0,0 +1,136 @@ +""" +OLED display module for ESP32 using SSD1306 controller. +""" +import time +try: + from machine import Pin, I2C + import ssd1306 + SIMULATION = False +except ImportError: + SIMULATION = True + +from .sensor import Sensor + + +class OLEDDisplay(Sensor): + """SSD1306 OLED display implementation.""" + + def __init__(self, name: str, scl_pin: int, sda_pin: int, width: int = 128, height: int = 64, + address: int = 0x3C, interval: int = 60): + """ + Initialize a new OLED display. + + Args: + name: The name of the display + scl_pin: The GPIO pin number for the SCL (clock) line + sda_pin: The GPIO pin number for the SDA (data) line + width: Display width in pixels (default: 128) + height: Display height in pixels (default: 64) + address: I2C address of the display (default: 0x3C) + interval: Refresh interval in seconds (default: 60) + """ + # Use sda_pin as the pin parameter for the Sensor base class + super().__init__(name, sda_pin, interval) + + self.scl_pin = scl_pin + self.sda_pin = sda_pin + self.width = width + self.height = height + self.address = address + self._values = [] + + # Initialize the display if not in simulation mode + if not SIMULATION: + try: + i2c = I2C(0, scl=Pin(scl_pin), sda=Pin(sda_pin)) + self._display = ssd1306.SSD1306_I2C(width, height, i2c, addr=address) + self._display.fill(0) # Clear the display + self._display.text("Initialized", 0, 0, 1) + self._display.show() + except Exception as e: + print(f"Error initializing OLED display: {e}") + self._display = None + else: + # In simulation mode, just print to console + print(f"Simulated OLED display initialized: {width}x{height}") + self._display = None + + def clear(self): + """ + Clear the display. + """ + if SIMULATION: + print("Simulated OLED display cleared") + else: + if self._display: + self._display.fill(0) + self._display.show() + + def display_text(self, text: str, x: int = 0, y: int = 0, color: int = 1): + """ + Display text at the specified position. + + Args: + text: The text to display + x: X coordinate (default: 0) + y: Y coordinate (default: 0) + color: Pixel color (1 for white, 0 for black, default: 1) + """ + if SIMULATION: + print(f"Simulated OLED display text at ({x}, {y}): {text}") + else: + if self._display: + self._display.text(text, x, y, color) + self._display.show() + + def display_values(self, values: list): + """ + Display a list of values on the OLED screen. + + Args: + values: List of values to display (strings or objects with __str__ method) + """ + self._values = values + + if SIMULATION: + print("Simulated OLED display values:") + for i, value in enumerate(values): + print(f" Line {i}: {value}") + else: + if self._display: + self._display.fill(0) # Clear the display + + # Display each value on a new line (8 pixels per line) + for i, value in enumerate(values): + if i * 10 < self.height: # Make sure we don't go off the screen + self._display.text(str(value), 0, i * 10, 1) + + self._display.show() + + def read(self) -> float: + """ + Update the display (placeholder to satisfy Sensor interface). + + Returns: + Always returns 1.0 to indicate success + """ + # This method is required by the Sensor interface but doesn't make sense for a display + # We'll just return a constant value + return 1.0 + + def get_metadata(self): + """ + Get display metadata. + + Returns: + A dictionary containing display metadata + """ + metadata = super().get_metadata() + metadata["scl_pin"] = self.scl_pin + metadata["sda_pin"] = self.sda_pin + metadata["width"] = self.width + metadata["height"] = self.height + metadata["address"] = self.address + metadata["type"] = "SSD1306" + metadata["values_count"] = len(self._values) + return metadata \ No newline at end of file diff --git a/src/esp_sensors/temperature.py b/src/esp_sensors/temperature.py index 2b3e208..7152798 100644 --- a/src/esp_sensors/temperature.py +++ b/src/esp_sensors/temperature.py @@ -23,7 +23,7 @@ class TemperatureSensor(Sensor): raise ValueError("Unit must be either 'C' or 'F'") self.unit = unit - def read(self) -> float: + def read_temperature(self) -> float: """ Read the current temperature. @@ -38,6 +38,15 @@ class TemperatureSensor(Sensor): self._last_reading = round(random.uniform(59.0, 86.0), 1) return self._last_reading + def read(self) -> float: + """ + Read the current temperature (wrapper for read_temperature). + + Returns: + The temperature reading as a float + """ + return self.read_temperature() + def get_metadata(self): """ Get sensor metadata including temperature unit. diff --git a/tests/test_oled_display.py b/tests/test_oled_display.py new file mode 100644 index 0000000..b3ce197 --- /dev/null +++ b/tests/test_oled_display.py @@ -0,0 +1,107 @@ +""" +Tests for the OLED display module. +""" +import pytest +from src.esp_sensors.oled_display import OLEDDisplay + + +def test_oled_display_initialization(): + """Test that an OLED display can be initialized with valid parameters.""" + display = OLEDDisplay("test_display", scl_pin=22, sda_pin=21) + assert display.name == "test_display" + assert display.scl_pin == 22 + assert display.sda_pin == 21 + assert display.pin == 21 # pin in base class is set to sda_pin + assert display.width == 128 + assert display.height == 64 + assert display.address == 0x3C + assert display.interval == 60 + assert display._values == [] + + +def test_oled_display_custom_parameters(): + """Test that an OLED display can be initialized with custom parameters.""" + display = OLEDDisplay( + "custom_display", + scl_pin=22, + sda_pin=21, + width=64, + height=32, + address=0x3D, + interval=30 + ) + assert display.name == "custom_display" + assert display.scl_pin == 22 + assert display.sda_pin == 21 + assert display.width == 64 + assert display.height == 32 + assert display.address == 0x3D + assert display.interval == 30 + + +def test_oled_display_read(): + """Test that reading from the display returns a success value.""" + display = OLEDDisplay("test_display", scl_pin=22, sda_pin=21) + reading = display.read() + assert reading == 1.0 + + +def test_oled_display_metadata(): + """Test that metadata includes the display parameters.""" + display = OLEDDisplay("test_display", scl_pin=22, sda_pin=21) + metadata = display.get_metadata() + assert metadata["name"] == "test_display" + assert metadata["pin"] == 21 + assert metadata["scl_pin"] == 22 + assert metadata["sda_pin"] == 21 + assert metadata["width"] == 128 + assert metadata["height"] == 64 + assert metadata["address"] == 0x3C + assert metadata["interval"] == 60 + assert metadata["type"] == "SSD1306" + assert metadata["values_count"] == 0 + + +def test_oled_display_values(): + """Test that display values are stored correctly.""" + display = OLEDDisplay("test_display", scl_pin=22, sda_pin=21) + + # Test with empty values + assert display._values == [] + + # Test with string values + test_values = ["Temperature: 25.0°C", "Humidity: 45.0%"] + display.display_values(test_values) + assert display._values == test_values + + # Check that metadata reflects the number of values + metadata = display.get_metadata() + assert metadata["values_count"] == 2 + + +def test_oled_display_clear(): + """Test that clearing the display works in simulation mode.""" + display = OLEDDisplay("test_display", scl_pin=22, sda_pin=21) + + # This is mostly a coverage test since we can't check the actual display in tests + display.clear() + + # Verify that clearing doesn't affect stored values + test_values = ["Temperature: 25.0°C"] + display.display_values(test_values) + display.clear() + assert display._values == test_values + + +def test_oled_display_text(): + """Test that displaying text works in simulation mode.""" + display = OLEDDisplay("test_display", scl_pin=22, sda_pin=21) + + # This is mostly a coverage test since we can't check the actual display in tests + display.display_text("Hello, World!") + + # Verify that displaying text doesn't affect stored values + test_values = ["Temperature: 25.0°C"] + display.display_values(test_values) + display.display_text("Hello, World!") + assert display._values == test_values \ No newline at end of file