Display Elements
Display elements are read-only UI components that show data from your device. These variables are updated programmatically and displayed to users in the web interface.
Import
from pydoover.ui import (
Variable,
NumericVariable,
TextVariable,
BooleanVariable,
DateTimeVariable,
)
Variable (Base Class)
The Variable class is the base class for all display elements. All specific variable types inherit from this class.
Constructor
Variable(
name: str,
display_name: str,
var_type: str,
curr_val: Any = NotSet,
precision: int = None,
ranges: list[Range] = None,
earliest_data_time: datetime = None,
default_zoom: str = None,
log_threshold: float = None,
**kwargs
)
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
name | str | Required | Unique identifier for the variable |
display_name | str | Required | Human-readable label shown in the UI |
var_type | str | Required | Type hint: "float", "string", "bool", "time" |
curr_val | Any | NotSet | Initial value of the variable |
precision | int | None | Decimal places for numeric rounding |
ranges | list[Range] | None | Value ranges for visual indicators |
earliest_data_time | datetime | None | Earliest available historical data time |
default_zoom | str | None | Default zoom level for the plot viewer |
log_threshold | float | None | Change threshold to trigger logging |
Common Properties and Methods
current_value
Gets or sets the current value of the variable.
# Get value temp = my_variable.current_value # Set value my_variable.current_value = 25.5
update()
Updates the variable's value with optional logging control.
my_variable.update(26.5) # Force a log entry my_variable.update(26.5, force_log=True)
add_ranges()
Adds one or more Range objects for visual indicators.
from pydoover.ui import Range, Colour
my_variable.add_ranges(
Range(label="Low", min_val=0, max_val=20, colour=Colour.blue),
Range(label="Normal", min_val=20, max_val=30, colour=Colour.green),
)
Logging Methods
# Check if a log request is pending
if my_variable.has_pending_log_request():
print("Log pending")
# Clear the log request flag
my_variable.clear_log_request()
NumericVariable
Represents numeric values (integers or floats) in the UI. Ideal for sensor readings, measurements, and counters.
Constructor
NumericVariable(
name: str,
display_name: str,
curr_val: Union[int, float] = None,
precision: int = None,
ranges: list[Range] = None,
form: Widget = None,
**kwargs
)
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
name | str | Required | Unique identifier |
display_name | str | Required | Label shown in UI |
curr_val | int or float | None | Initial numeric value |
precision | int | None | Decimal places for display |
ranges | list[Range] | None | Visual range indicators |
form | Widget | None | Display widget type (gauge, etc.) |
Example
from pydoover.ui import NumericVariable, Range, Colour, Widget
# Basic numeric variable
temperature = NumericVariable(
name="temperature",
display_name="Temperature",
curr_val=25.5,
precision=1
)
# With ranges for visual feedback
battery_level = NumericVariable(
name="battery",
display_name="Battery Level",
curr_val=85,
precision=0,
ranges=[
Range(label="Low", min_val=0, max_val=20, colour=Colour.red),
Range(label="Medium", min_val=20, max_val=50, colour=Colour.yellow),
Range(label="Good", min_val=50, max_val=100, colour=Colour.green),
]
)
# With gauge widget
pressure = NumericVariable(
name="pressure",
display_name="Pressure (PSI)",
curr_val=45.2,
precision=1,
form=Widget.radial,
ranges=[
Range(label="Normal", min_val=30, max_val=60, colour=Colour.green, show_on_graph=True),
]
)
# Updating the value
temperature.current_value = 26.3
# or
temperature.update(26.3)
With Logging Threshold
# Only log when value changes by more than 0.5
temperature = NumericVariable(
name="temperature",
display_name="Temperature",
curr_val=25.5,
precision=1,
log_threshold=0.5
)
Real-World Example: Engine Monitoring Dashboard
This example from a production pump controller shows NumericVariables with radial gauges for engine monitoring:
from pydoover.ui import NumericVariable, Range, Colour
# RPM gauge with color ranges
rpm_gauge = NumericVariable(
"pumprpm",
"Engine RPM",
precision=0,
form="radialGauge",
ranges=[
Range(min_val=0, max_val=800, colour=Colour.blue),
Range(min_val=800, max_val=2200, colour=Colour.green),
],
)
# Engine load with multi-zone ranges
engine_load = NumericVariable(
"engineLoad",
"Engine Load (%)",
precision=0,
ranges=[
Range(min_val=0, max_val=15, colour=Colour.blue),
Range(min_val=15, max_val=100, colour=Colour.green),
],
)
# Coolant temperature with warning zone
coolant_temp = NumericVariable(
"coolantTemp",
"Coolant Temp (C)",
precision=0,
ranges=[
Range(min_val=0, max_val=50, colour=Colour.blue),
Range(min_val=50, max_val=90, colour=Colour.green),
Range(min_val=90, max_val=120, colour=Colour.yellow), # Warning zone
],
)
# Update from hardware state
def update_readings(self, k37_state):
if k37_state.is_contactable:
self.rpm_gauge.update(k37_state.rpm)
self.engine_load.update(k37_state.load)
self.coolant_temp.update(k37_state.coolant_temp)
else:
# Clear readings when disconnected
for gauge in (self.rpm_gauge, self.engine_load, self.coolant_temp):
gauge.update(None)
Source: pump_station_controller
TextVariable
Represents string/text values in the UI. Useful for status messages, device names, and textual data.
Constructor
TextVariable(
name: str,
display_name: str,
curr_val: str = None,
**kwargs
)
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
name | str | Required | Unique identifier |
display_name | str | Required | Label shown in UI |
curr_val | str | None | Initial text value |
Example
from pydoover.ui import TextVariable
# Status indicator
status = TextVariable(
name="status",
display_name="Device Status",
curr_val="Running"
)
# Device information
firmware = TextVariable(
name="firmware_version",
display_name="Firmware Version",
curr_val="v2.1.3"
)
# Update the value
status.current_value = "Idle"
BooleanVariable
Represents boolean (true/false) values in the UI. Useful for on/off states, flags, and binary indicators.
Constructor
BooleanVariable(
name: str,
display_name: str,
curr_val: bool = None,
log_threshold: float = 0,
**kwargs
)
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
name | str | Required | Unique identifier |
display_name | str | Required | Label shown in UI |
curr_val | bool | None | Initial boolean value |
log_threshold | float | 0 | Log every change by default; None disables logging |
Example
from pydoover.ui import BooleanVariable
# On/off indicator
power_state = BooleanVariable(
name="power_on",
display_name="Power",
curr_val=True
)
# Alarm state
alarm_active = BooleanVariable(
name="alarm",
display_name="Alarm Active",
curr_val=False
)
# Don't log changes
silent_flag = BooleanVariable(
name="processing",
display_name="Processing",
curr_val=False,
log_threshold=None # Disable change logging
)
# Update
power_state.current_value = False
Real-World Example: Motor Control Status
This example from a production motor control application shows how BooleanVariables track operational states:
from pydoover.ui import BooleanVariable, Submodule
# Create status indicators for motor controller
is_running = BooleanVariable(
name="is_running",
display_name="Motor Running",
curr_val=False
)
ignition_on = BooleanVariable(
name="ignition_on",
display_name="Ignition On",
curr_val=False
)
estopped = BooleanVariable(
name="estopped",
display_name="Emergency Stop Active",
curr_val=False
)
manual_mode = BooleanVariable(
name="manual_mode",
display_name="Manual Mode",
curr_val=False
)
# Group status indicators
status_module = Submodule(
name="motor_status",
display_name="Motor Status",
children=[is_running, ignition_on, estopped, manual_mode]
)
# Update from hardware state
def update_status(self):
is_running.current_value = self.state == "running_user"
ignition_on.current_value = await self.get_input(self.ignition_pin)
estopped.current_value = await self.get_input(self.estop_pin)
Source: small-motor-control
DateTimeVariable
Represents date and time values in the UI. Useful for timestamps, scheduled times, and time-based data.
Constructor
DateTimeVariable(
name: str,
display_name: str,
curr_val: Union[datetime, int] = None,
**kwargs
)
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
name | str | Required | Unique identifier |
display_name | str | Required | Label shown in UI |
curr_val | datetime or int | None | Initial value (datetime object or Unix timestamp) |
Example
from datetime import datetime
from pydoover.ui import DateTimeVariable
# Last update timestamp
last_updated = DateTimeVariable(
name="last_updated",
display_name="Last Updated",
curr_val=datetime.now()
)
# From Unix timestamp
event_time = DateTimeVariable(
name="event_time",
display_name="Event Time",
curr_val=1706500000 # Unix timestamp
)
# Update with datetime
last_updated.current_value = datetime.now()
# Update with timestamp
last_updated.current_value = 1706501234
Real-World Example: Application Uptime Tracking
This example from a Doover application template shows a DateTimeVariable used to display application uptime:
import time
from pydoover import ui
class SampleUI:
def __init__(self):
self.uptime = ui.DateTimeVariable("uptime", "Started")
class SampleApplication(Application):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.started: float = time.time()
async def main_loop(self):
# Update uptime to show elapsed time since start
self.ui.uptime.update(self.started)
Source: app-template
Common Element Properties
All UI elements (both display and interactive) inherit common properties from the Element base class. These properties work identically on Variables, Actions, Parameters, and other UI components:
| Property | Type | Description |
|---|---|---|
name | str | Unique identifier |
display_name | str | Human-readable label |
position | int | Display order position |
hidden | bool | Whether element is hidden |
help_str | str | Help text for the element |
verbose_str | str | Verbose description |
conditions | dict | Conditional display rules |
Example with Common Properties
temperature = NumericVariable(
name="temperature",
display_name="Temperature",
curr_val=25.5,
position=10, # Display order
hidden=False, # Visible
help_str="Current ambient temperature in Celsius",
)
Working with Ranges
Ranges provide visual indicators for numeric values. They can show acceptable ranges, warning zones, or other meaningful boundaries.
from pydoover.ui import NumericVariable, Range, Colour
tank_level = NumericVariable(
name="tank_level",
display_name="Tank Level (%)",
curr_val=65,
ranges=[
Range(
label="Empty",
min_val=0,
max_val=10,
colour=Colour.red,
show_on_graph=True
),
Range(
label="Low",
min_val=10,
max_val=30,
colour=Colour.orange,
show_on_graph=True
),
Range(
label="Normal",
min_val=30,
max_val=80,
colour=Colour.green,
show_on_graph=True
),
Range(
label="Full",
min_val=80,
max_val=100,
colour=Colour.blue,
show_on_graph=True
),
]
)
Complete Example
from datetime import datetime
from pydoover.ui import (
UIManager,
NumericVariable,
TextVariable,
BooleanVariable,
DateTimeVariable,
Submodule,
Range,
Colour,
)
# Create UI manager
ui = UIManager(app_key="sensor_monitor", client=my_client)
# Create display variables
temperature = NumericVariable(
name="temperature",
display_name="Temperature (C)",
curr_val=22.5,
precision=1,
ranges=[
Range("Cold", 0, 15, Colour.blue),
Range("Normal", 15, 28, Colour.green),
Range("Hot", 28, 50, Colour.red),
]
)
humidity = NumericVariable(
name="humidity",
display_name="Humidity (%)",
curr_val=45,
precision=0
)
status = TextVariable(
name="status",
display_name="Sensor Status",
curr_val="OK"
)
sensor_online = BooleanVariable(
name="sensor_online",
display_name="Sensor Online",
curr_val=True
)
last_reading = DateTimeVariable(
name="last_reading",
display_name="Last Reading",
curr_val=datetime.now()
)
# Organize in a submodule
sensor_data = Submodule(
name="sensor_data",
display_name="Sensor Readings",
children=[
temperature,
humidity,
status,
sensor_online,
last_reading,
]
)
# Add to UI
ui.add_children(sensor_data)
# Update values periodically
def update_sensors():
temperature.current_value = read_temperature()
humidity.current_value = read_humidity()
sensor_online.current_value = check_sensor_connection()
last_reading.current_value = datetime.now()
if not sensor_online.current_value:
status.current_value = "Sensor Offline"
elif temperature.current_value > 28:
status.current_value = "High Temperature Warning"
else:
status.current_value = "OK"
ui.handle_comms()
See Also
- UIManager - Managing the UI
- Interactive Elements - User input elements
- Containers - Organizing elements
- Styling - Colors, ranges, and widgets