Skip to main content

Overview

The Alerts & Notifications system monitors water quality metrics in real-time and triggers notifications when sensor values fall outside configured thresholds. Alerts support multiple notification channels and include approval workflows for critical conditions.

Threshold-Based

Configure min/max ranges for each sensor type

Multi-Channel

Email (Resend) and push notifications (OneSignal)

Approval Workflow

Critical alerts require owner approval before team notification

Alert Types

Alerts are categorized by water quality severity:
Critical water quality issues requiring immediate action
  • Values indicate unsafe conditions
  • Triggers approval workflow
  • Highest priority notifications
  • Requires owner/administrator approval before team notification
AlertType.DANGEROUS = "dangerous"
Below acceptable standards
  • Water quality is degraded
  • Immediate notification to configured guests
  • No approval required
AlertType.POOR = "poor"
Acceptable but not optimal
  • Water quality is within limits but could be better
  • Standard notification delivery
AlertType.MODERATE = "moderate"
Good water quality
  • Parameters within healthy ranges
  • Optional notification for monitoring
AlertType.GOOD = "good"
Optimal water quality
  • All parameters in excellent range
  • Informational notifications
AlertType.EXCELLENT = "excellent"

Alert Configuration

Create an Alert

Configure threshold-based monitoring for a meter:
POST /api/alerts/
Content-Type: application/json
Authorization: Bearer {access_token}

{
  "title": "Critical pH Alert",
  "type": "dangerous",
  "workspace_id": "workspace_123",
  "meter_id": "meter_456",
  "parameters": {
    "ph": {
      "min": 6.5,
      "max": 8.5
    },
    "tds": {
      "min": 0,
      "max": 500
    },
    "temperature": {
      "min": 0,
      "max": 30
    },
    "conductivity": {
      "min": 0,
      "max": 800
    },
    "turbidity": {
      "min": 0,
      "max": 5
    }
  },
  "guests": [
    "[email protected]",
    "[email protected]"
  ]
}
Response:
{
  "message": "Alert created successfully",
  "alert": {
    "id": "alert_789",
    "title": "Critical pH Alert",
    "type": "dangerous",
    "workspace_id": "workspace_123",
    "meter_id": "meter_456",
    "owner": "user_owner",
    "parameters": { /* ... */ },
    "guests": ["[email protected]", "[email protected]"]
  }
}

Parameter Model

class RangeValue(BaseModel):
    min: float
    max: float

    @field_validator('max')
    @classmethod
    def validate_max_greater_than_min(cls, v, info):
        if 'min' in info.data and v <= info.data['min']:
            raise ValueError('max must be greater than min')
        return v

class Parameter(BaseModel):
    ph: RangeValue
    tds: RangeValue
    temperature: RangeValue
    conductivity: RangeValue
    turbidity: RangeValue
Source: ~/workspace/source/app/share/parameters/domain/model.py:4
All five sensor parameters must be configured for each alert. The max value must be greater than min for each range.

Notification Channels

Email Notifications (Resend)

Alerts are delivered via email using the Resend API:
  • HTML templated emails with professional formatting
  • Workspace and meter context included
  • Detected sensor values that triggered the alert
  • Approval status for critical alerts
Email Template Features:
# Guest invitation email
html_template.get_guest_workspace(
    guest_name="John Doe",
    inviter_name="Jane Smith",
    workspace_id="workspace_123"
)

# Critical alert notification email
html_template.get_critical_alert_notification_email(
    approver_name="Owner Name",
    detected_values=[{"parameter": "ph", "value": 9.2}],
    meter="Lake Monitor Station 1",
    workspace="River Monitoring Project"
)
See: ~/workspace/source/app/share/email/service/resend_email.py

Push Notifications (OneSignal)

Real-time push notifications via OneSignal:
  • Mobile device support (iOS and Android)
  • Web push notifications
  • Rich notification content with alert details
  • Deep linking to relevant meter data
Source: ~/workspace/source/app/share/messages/service/onesignal_service.py

Notification Workflow

Standard Alerts (Good, Moderate, Poor, Excellent)

1

Threshold Breach Detected

System continuously monitors sensor readings against configured thresholds.
2

Alert Triggered

When a value falls outside the configured range, an alert is triggered.
3

Notifications Sent

Email and push notifications are immediately sent to all configured guests.
4

Notification Logged

Alert event is recorded in notification history with status: "accepted".

Critical Alerts (Dangerous)

1

Threshold Breach Detected

Dangerous condition detected in sensor readings.
2

Pending Notification Created

Notification created with status: "pending" and sent to workspace owner/administrators.
3

Approval Required

Owner or administrator reviews the alert details:
GET /api/alerts/notifications/{notification_id}/
Authorization: Bearer {access_token}
4

Accept or Reject

Owner/administrator makes decision:
PUT /api/alerts/notifications/status/{notification_id}/
Content-Type: application/json
Authorization: Bearer {access_token}

{
  "status": "accepted"  // or "rejected"
}
5

Team Notification (if accepted)

If accepted, detailed notification emails sent to all configured guests with:
  • Approver name
  • Detected parameter values
  • Meter and workspace context

Notification Status

class NotificationStatus(str, Enum):
    PENDING = "pending"   # Awaiting approval (dangerous alerts)
    ACCEPTED = "accepted" # Approved and sent to team
    REJECTED = "rejected" # Dismissed by owner
Once a notification status is set to accepted or rejected, it cannot be changed again.

Alert Management

List Alerts

Query alerts with optional filters:
GET /api/alerts/?
  workspace_id=workspace_123&
  meter_id=meter_456&
  type=dangerous
Authorization: Bearer {access_token}

Get Alert Details

GET /api/alerts/{alert_id}/
Authorization: Bearer {access_token}

Update Alert Configuration

PUT /api/alerts/{alert_id}/
Content-Type: application/json
Authorization: Bearer {access_token}

{
  "title": "Updated Alert Title",
  "type": "moderate",
  "parameters": {
    "ph": {
      "min": 6.0,
      "max": 9.0
    },
    // ... other parameters
  },
  "guests": ["[email protected]"]
}

Delete Alert

DELETE /api/alerts/{alert_id}/
Authorization: Bearer {access_token}

Notification History

Get User Notifications

Retrieve notification history for the authenticated user:
GET /api/alerts/notifications/?
  type=dangerous&
  is_read=false&
  status=pending&
  convert_timestamp=true
Authorization: Bearer {access_token}
Query Parameters:
  • type: Filter by alert type (dangerous, poor, moderate, good, excellent)
  • is_read: Filter by read status (true/false)
  • status: Filter by notification status (pending, accepted, rejected)
  • convert_timestamp: Convert Unix timestamps to datetime strings
Response:
{
  "message": "Notifications retrieved successfully",
  "notifications": [
    {
      "id": "notif_123",
      "title": "Critical pH Alert",
      "body": "pH level exceeded safe threshold: 9.2",
      "read": false,
      "status": "pending",
      "datetime": "2024-01-15T14:30:00Z",
      "alert_id": "alert_789",
      "record_parameters": [
        {"parameter": "ph", "value": 9.2}
      ]
    }
  ]
}

Mark Notification as Read

PUT /api/alerts/notifications/{notification_id}/
Authorization: Bearer {access_token}

Get Notification Details

GET /api/alerts/notifications/{notification_id}/
Authorization: Bearer {access_token}

Priority Parameters

Certain parameters are prioritized for critical alerts:
class PriorityParameters(list[str], Enum):
    parameters: list[str] = ["ph", "turbidity"]
pH and turbidity are considered high-priority indicators of water safety.

Data Models

Alert Model

class AlertData(BaseModel):
    title: str
    type: AlertType
    workspace_id: str
    meter_id: str
    owner: str
    parameters: Parameter | None
    guests: list[str]

class Alert(AlertData):
    id: str
Source: ~/workspace/source/app/features/alerts/domain/model.py:6

Notification Model

class RecordParameter(BaseModel):
    parameter: str  # Sensor type (ph, tds, etc.)
    value: float    # Measured value

class NotificationBody(BaseModel):
    id: str = None
    read: bool = False
    title: str
    body: str
    user_ids: list[str]
    timestamp: float | None = None
    status: NotificationStatus | None = None
    alert_id: str | None = None
    record_parameters: list[RecordParameter] = []
    aproved_by: str | None = None
Source: ~/workspace/source/app/share/messages/domain/model.py:72

Best Practices

Appropriate Thresholds

Set thresholds based on local water quality standards and use cases

Strategic Guest Lists

Include relevant stakeholders who can take action on alerts

Alert Type Selection

Use “dangerous” type sparingly for truly critical conditions

Regular Review

Periodically review and adjust thresholds based on historical data

Prompt Approval

Respond quickly to pending dangerous alerts to enable team notification

Test Notifications

Verify notification delivery channels are working correctly

Example: Complete Alert Setup

import requests

# Create alert for pH monitoring
alert_response = requests.post(
    "https://api.example.com/api/alerts/",
    headers={"Authorization": f"Bearer {token}"},
    json={
        "title": "Drinking Water pH Monitor",
        "type": "dangerous",
        "workspace_id": "workspace_123",
        "meter_id": "meter_456",
        "parameters": {
            "ph": {"min": 6.5, "max": 8.5},
            "tds": {"min": 0, "max": 500},
            "temperature": {"min": 0, "max": 30},
            "conductivity": {"min": 0, "max": 800},
            "turbidity": {"min": 0, "max": 5}
        },
        "guests": [
            "[email protected]",
            "[email protected]"
        ]
    }
)

print(f"Alert created: {alert_response.json()['alert']['id']}")

Build docs developers (and LLMs) love