Skip to content

Quick Start

This guide walks you through creating and running a Doover application using the doover-cli wizard. By the end, you'll have a working application running locally that you can customize and deploy to the Doover platform.

Prerequisites

Before starting, ensure you have:

  • Python 3.11 or higher
  • Docker installed and running
  • A Doover account (sign up at my.doover.com)

Step 1: Install the Doover CLI

Install the Doover CLI using one of these methods:

# Using uv (Recommended)
uv tool install doover-cli

# Using pipx
pipx install doover-cli

# Using pip
pip install doover-cli

Verify the installation:

doover --version

Step 2: Authenticate

Log in to your Doover account:

doover login

This opens a browser window for authentication. Once complete, your credentials are stored locally for future use.

Step 3: Create Your Application

Run the application creation wizard:

doover app create

The wizard guides you through the setup:

What is the name of your app? my-sensor-app
Description: Monitors temperature sensors and sends alerts
Would you like me to initiate a git repository? [Y/n] y
What is the container registry for your app? ghcr.io/getdoover
What is the owner organisation's key (on Doover)? my-org
What is the container registry profile key on Doover? my-registry

Fetching template repository...
Renaming template files...
Updating config...

Done!

The wizard creates a complete project with this structure:

my-sensor-app/
├── src/
│   └── my_sensor_app/
│       ├── __init__.py        # Entry point
│       ├── application.py     # Main application logic
│       ├── app_config.py      # Configuration schema
│       ├── app_ui.py          # UI elements
│       └── app_state.py       # State machine (optional)
├── simulators/
│   ├── sample/
│   │   └── main.py            # Simulator for local testing
│   └── docker-compose.yml     # Local development setup
├── tests/
│   └── test_imports.py
├── doover_config.json         # Application metadata
├── pyproject.toml
├── Dockerfile
└── README.md

Step 4: Run Locally

Navigate to your application directory and start it:

cd my-sensor-app
doover app run

This starts three Docker containers:

  • device_agent - Simulates the Doover device agent
  • simulator - Provides mock data via tags
  • your application - The application you just created

You'll see logs from all three containers in your terminal.

Step 5: View in Browser

While your app is running, open the channel viewer to see your application's data:

doover app channels

This opens the Doover web interface connected to your local instance, where you can see UI elements, variables, and interact with your application.

Understanding the Generated Code

The wizard generates a working application based on the app-template. Here's what each file does:

application.py

The main application class with lifecycle methods:

from pydoover.docker import Application
from pydoover import ui

class SampleApplication(Application):
    async def setup(self):
        """Called once when the application starts."""
        self.ui = SampleUI()
        self.ui_manager.add_children(*self.ui.fetch())

    async def main_loop(self):
        """Called repeatedly (default: every 1 second)."""
        # Update UI, read sensors, process logic
        self.ui.is_working.update(True)

    @ui.callback("send_alert")
    async def on_send_alert(self, new_value):
        """Called when user presses the send_alert button."""
        await self.publish_to_channel("significantAlerts", "Alert!")

app_config.py

Defines configurable parameters for your application:

from pydoover import config

class SampleConfig(config.Schema):
    def __init__(self):
        self.outputs_enabled = config.Boolean("Digital Outputs Enabled", default=True)
        self.funny_message = config.String("A Funny Message")

app_ui.py

Defines the UI elements users see in the Doover dashboard:

from pydoover import ui

class SampleUI:
    def __init__(self):
        self.is_working = ui.BooleanVariable("is_working", "We Working?")
        self.send_alert = ui.Action("send_alert", "Send Alert")
        self.battery = ui.Submodule("battery", "Battery Module")
        # ... more UI elements

Customizing Your Application

Modify the Main Loop

Edit application.py to add your logic:

async def main_loop(self):
    # Read from simulator or real hardware
    sensor_value = self.get_tag("random_value", self.config.sim_app_key.value)

    # Update UI
    self.ui.sensor_reading.update(sensor_value)

    # React to thresholds
    if sensor_value > 80:
        await self.publish_to_channel("alerts", f"High value: {sensor_value}")

Add UI Elements

Edit app_ui.py to add variables and controls:

# Add a numeric variable with color ranges
self.temperature = ui.NumericVariable(
    "temperature",
    "Temperature (°C)",
    precision=1,
    ranges=[
        ui.Range("Cold", 0, 15, ui.Colour.blue),
        ui.Range("Normal", 15, 28, ui.Colour.green),
        ui.Range("Hot", 28, 50, ui.Colour.red),
    ]
)

Add Configuration Options

Edit app_config.py to add user-configurable settings:

self.alert_threshold = config.Number(
    "Alert Threshold",
    default=80.0,
    description="Value above which alerts are triggered"
)

Development Workflow

# Make code changes, then:

# Check code quality
doover app lint --fix
doover app format --fix

# Run tests
doover app test

# Rebuild and run
doover app build
doover app run

# When ready, publish to Doover
doover app publish

Next Steps

Now that you have a running application, explore these topics: