MyEMS Core Features & Business Logic
This document provides an in-depth explanation of the core business logic, features, and technical implementation of the MyEMS Energy Management System.
Table of Contents
- System Core Concepts
- Energy Management Features
- Billing & Cost Management
- Carbon Emissions Tracking
- Data Processing Pipeline
- Advanced Features
- Technical Implementation
- API Architecture
- Database Design Patterns
System Core Concepts
Hierarchical Organization Structure
MyEMS uses a hierarchical multi-level architecture to represent organizational structures:
Enterprise
βββ Site/Campus
βββ Building
βββ Floor
βββ Space/Room
βββ Equipment/Systems
βββ Meters
Key Components:
- Sites: Top-level organizational units (campuses, facilities)
- Buildings: Individual structures within a site
- Floors: Levels within buildings
- Spaces: Individual rooms or areas (offices, conference rooms, storage)
- Equipment: Energy-consuming systems (HVAC, lighting, motors, compressors)
- Meters: Physical measurement devices (electricity meters, water meters, gas meters)
Benefits: - Enables energy tracking at any organizational level - Supports cost allocation and chargeback - Allows drill-down analysis from building to equipment level - Facilitates energy savings tracking and benchmarking
Multi-Tenancy Support
MyEMS supports multiple independent organizations using the same system:
- Tenants: Independent organizational entities
- Cost Centers: Cost allocation units within tenants
- Independent Billing: Each tenant maintains separate billing records
- Data Isolation: Tenant data is logically separated while sharing infrastructure
- Permission Control: Granular permissions per tenant
Energy Category System
Energy types are managed through configurable categories:
| Category | Examples | Unit | Purpose |
|---|---|---|---|
| Electricity | Grid power, solar generation, backup power | kWh | Primary energy tracking |
| Water | Municipal supply, well water | mΒ³ (cubic meters) | Resource consumption |
| Gas | Natural gas, biogas | mΒ³ or kg | Fuel consumption |
| Cooling | Chilled water, district cooling | kWh equivalent | HVAC tracking |
| Heating | Hot water, district heating, steam | kWh equivalent | Thermal energy tracking |
| Other | Fuel, compressed air, etc. | Unit-specific | Specialized tracking |
Dynamic Configuration: - Custom energy categories can be added - Each category has configurable units - Emission factors per category for carbon calculations - Tariffs applied per category and cost center
Energy Management Features
1. Meter Management & Data Collection
Meter Types Supported:
- Physical Meters
- Connected via Modbus TCP protocol
- Real-time data acquisition at configurable intervals
- Multiple register configuration (energy, power, voltage, current, power factor, etc.)
- Automatic data buffering and error handling
-
Disconnection resilience with retry logic
-
Offline Meters
- Manual entry or bulk import via Excel
- For historical data or non-connected devices
- Supports date-range data entry
-
Audit trail for manual entries
-
Virtual Meters
- Software-calculated aggregations of physical meters
- Formula-based calculations (additions, subtractions, weighted averages)
- Useful for:
- Sub-meter aggregation (e.g., HVAC = heating + cooling)
- Energy flows (e.g., gross consumption - generation)
- Normalized comparisons
- Real-time calculation from underlying meters
Meter Configuration:
Physical Meter Properties:
βββ Identification
β βββ Meter ID (unique identifier)
β βββ Name (display name)
β βββ Description
β βββ Serial Number
βββ Connection
β βββ Protocol (Modbus TCP, MQTT, HTTP)
β βββ Gateway/Data Source
β βββ Register Mapping
βββ Energy Properties
β βββ Energy Category (electricity, water, gas, etc.)
β βββ Energy Item (kWh, kW, reactive, etc.)
β βββ Unit
β βββ Calibration/Multiplier
βββ Business Properties
βββ Associated Equipment
βββ Location/Space
βββ Cost Center (for billing)
βββ Installation Date
Data Acquisition Flow:
Physical Device
β
Modbus TCP Service (myems-modbus-tcp)
ββ Read registers at interval (e.g., every 15 minutes)
ββ Apply multipliers (e.g., 0.01 kWh per register unit)
ββ Buffer in memory for batching
ββ Write to historical database
β
Raw Data Storage
ββ Table: meter_instantaneous_data (latest values)
ββ Table: meter_hourly_data (aggregated hourly)
2. Data Normalization
Purpose: Convert raw meter readings into standardized, comparable energy metrics.
Normalization Process:
Raw Meter Data (Register Values)
β
Step 1: Apply Calibration Factors
ββ Multiply by meter calibration factor (e.g., 0.01)
ββ Account for meter-specific characteristics
ββ Example: Raw value 1234 Γ 0.01 = 12.34 kWh
β
Step 2: Unit Conversion
ββ Convert to standard units (kWh, mΒ³, etc.)
ββ Handle unit transformations (Wh β kWh, cmΒ³ β mΒ³)
ββ Maintain precision for billing
β
Step 3: Meter Aggregation
ββ Combine related meters (e.g., 3-phase electricity)
ββ Apply weighting factors if needed
ββ Validate totals for consistency
β
Step 4: Virtual Meter Calculation
ββ Apply formulas (addition, subtraction, division)
ββ Example: Total = Meter1 + Meter2 - Meter3
ββ Calculate derived metrics
β
Step 5: Data Repair
ββ Fill gaps in missing data via interpolation
ββ Detect and fix anomalies
ββ Validate data monotonicity (no negative consumption)
ββ Handle meter resets and rollovers
β
Normalized Energy Data (Historical Database)
Key Calculations:
# Basic normalization
normalized_value = raw_value Γ meter_calibration Γ unit_conversion_factor
# Virtual meter with formula
virtual_meter_value = (meter1 + meter2) - meter3
# Handle meter reset (e.g., 99999 β 0)
if current < previous:
actual_consumption = current + (meter_max - previous)
else:
actual_consumption = current - previous
3. Real-Time Monitoring
Live Dashboard Features:
- Instantaneous View: Real-time energy consumption displayed as active power (kW)
- Status Indicators: Green (normal), yellow (warning), red (critical)
- Trend Indicators: Up/down arrows showing consumption increase/decrease
- Comparisons:
- vs. same time yesterday
- vs. average of past week/month
- vs. target/baseline
- Automatic Refresh: Updates at configurable intervals (typically 5-15 minutes)
Real-Time Data Pipeline:
Meter β Acquisition Service β Instantaneous Table β API Cache β Web UI
β
Hourly Aggregation
β
Historical Table
Performance Optimization:
- Redis caching of frequently accessed metrics
- Materialized hourly/daily/monthly aggregations
- Pre-calculated statistics to avoid runtime computation
- Lazy loading of detailed data
4. Historical Analysis & Trends
Time-Series Analysis Features:
- Hourly Data: Detailed consumption every hour
- Daily Aggregation: Sum of hourly values
- Monthly Aggregation: Sum of daily values
- Peak/Off-Peak Analysis: Time-of-use consumption patterns
- Seasonal Comparison: Year-over-year trends
- Baseline Deviation: Comparison to expected consumption
Trend Calculations:
Daily Pattern Analysis:
- Peak hours (e.g., 9 AM - 5 PM)
- Off-peak hours (e.g., 8 PM - 7 AM)
- Weekend vs weekday differences
- Holiday impact on consumption
Comparison Metrics:
- Same-day-last-year comparison
- Same-period average
- Trend slope (increasing/decreasing)
- Volatility (standard deviation)
Anomaly Detection:
- Spike detection (consumption > 1.5 Γ average)
- Anomalous patterns (e.g., 24/7 operation)
- Sudden changes (> 20% increase)
Report Types:
- Consumption Report: Total usage by time period
- Comparison Report: Current vs baseline/target
- Trend Report: Historical patterns and forecasting
- Peak Load Report: Maximum demand analysis
- Efficiency Report: Usage per unit (e.g., kWh per square meter)
Billing & Cost Management
Multi-Tariff Billing System
MyEMS supports complex billing scenarios with multiple tariff structures:
Tariff Types:
1. Time-of-Use (TOU) Tariff
ββ Peak hours (e.g., 9 AM - 9 PM): $0.15/kWh
ββ Off-peak hours (9 PM - 9 AM): $0.08/kWh
ββ Applied based on consumption timing
2. Tiered/Stepped Tariff
ββ First 1000 kWh: $0.10/kWh
ββ Next 1000 kWh: $0.12/kWh
ββ Above 2000 kWh: $0.15/kWh
ββ Applied based on total consumption
3. Demand Charge Tariff
ββ Energy charge: $0.10/kWh
ββ Demand charge: $10/kW of peak power
ββ Applies to peak usage during period
4. Fixed + Variable Tariff
ββ Fixed monthly charge: $50
ββ Variable charge: $0.12/kWh
ββ Total = Fixed + (consumption Γ variable rate)
5. Power Factor Tariff
ββ Base rate: $0.10/kWh
ββ Power factor < 0.95: +5% surcharge
ββ Power factor > 0.98: -3% discount
ββ Encourages efficient reactive load management
6. Seasonal Tariff
ββ Summer rate: $0.15/kWh (Jun-Aug)
ββ Winter rate: $0.18/kWh (Dec-Feb)
ββ Spring/Fall rate: $0.12/kWh (Mar-May, Sep-Nov)
ββ Reflects seasonal demand differences
Billing Calculation Process
Step-by-Step Billing Algorithm:
For Each Meter in System:
Step 1: Retrieve Meter Configuration
ββ Get meter ID, energy category, cost center
ββ Get associated tariff(s)
ββ Get applicable dates for tariff changes
Step 2: Determine Billing Period
ββ Get latest processed billing timestamp
ββ Calculate time gap since last processing
ββ Fetch energy data for unprocessed period
Step 3: Aggregate Energy Consumption
ββ Sum hourly energy values by tariff period
β ββ If TOU: separate peak and off-peak hours
β ββ If tiered: sum total consumption
β ββ If seasonal: apply seasonal rates
ββ Handle overlapping rates during transitions
Step 4: Apply Tariff Rules
ββ For each energy block:
β ββ Determine applicable tariff
β ββ Apply tariff formula
β ββ Calculate block cost
ββ Sum all blocks for total period cost
Step 5: Calculate Final Billing
ββ Subtotal = sum of all blocks
ββ Apply adjustments:
β ββ Surcharges (e.g., grid service charges)
β ββ Discounts (e.g., volume discounts)
β ββ Taxes (VAT, excise tax, etc.)
ββ Final billing amount = Subtotal + adjustments - credits
Step 6: Store Billing Record
ββ Create billing_ledger entry
ββ Record consumption and cost
ββ Mark processed period
ββ Enable future incremental processing
Pseudo-Code Example:
def calculate_meter_billing(meter_id, start_time, end_time):
"""Calculate billing for a meter during a period"""
# Get meter and tariff info
meter = get_meter(meter_id)
tariff = get_tariff(meter.cost_center_id)
# Aggregate consumption by tariff period
consumption_data = {
'peak': query_energy(meter_id, 'peak', start_time, end_time),
'off_peak': query_energy(meter_id, 'off_peak', start_time, end_time)
}
# Apply tariff rates
billing = 0.0
if tariff.type == 'TOU':
# Time-of-use tariff
billing = (consumption_data['peak'] * tariff.peak_rate +
consumption_data['off_peak'] * tariff.off_peak_rate)
elif tariff.type == 'TIERED':
# Tiered/stepped tariff
total_consumption = sum(consumption_data.values())
cumulative = 0
for tier in tariff.tiers:
tier_end = tier.threshold
tier_start = tariff.tiers[tier_idx - 1].threshold if tier_idx > 0 else 0
tier_consumption = min(tier_end, total_consumption) - cumulative
if tier_consumption > 0:
billing += tier_consumption * tier.rate
cumulative = tier_end
if total_consumption <= tier_end:
break
# Apply adjustments
subtotal = billing
tax = subtotal * tariff.tax_rate
surcharge = tariff.surcharge_amount
total_billing = subtotal + tax + surcharge
return {
'consumption': sum(consumption_data.values()),
'cost': total_billing,
'details': {
'subtotal': subtotal,
'tax': tax,
'surcharge': surcharge
}
}
Cost Allocation & Chargeback
Hierarchical Cost Distribution:
Building Total Cost: $10,000
ββ Allocated to 3 Tenants proportional to energy use
β ββ Tenant A: 40% usage β $4,000
β ββ Tenant B: 35% usage β $3,500
β ββ Tenant C: 25% usage β $2,500
β
ββ For Tenant A:
ββ Cost Centers within tenant
β ββ Operations: 60% β $2,400
β ββ Support: 40% β $1,600
β
ββ For Operations Cost Center:
ββ Departments
β ββ Department 1: 45% β $1,080
β ββ Department 2: 55% β $1,320
Carbon Emissions Tracking
Emission Factor Management
Carbon Calculation Basis:
Carbon Emissions = Energy Consumption Γ Emission Factor
Where Emission Factor depends on:
1. Energy Type (electricity, natural gas, etc.)
2. Geographic Region (grid mix, fuel sources)
3. Time Period (seasonal grid variations)
4. Calculation Standard (GHG Protocol, ISO 14064, etc.)
Emission Factors by Energy Type:
| Energy Type | Typical Factor | Source | Note |
|---|---|---|---|
| Electricity | 0.45 kg COβ/kWh | Grid average | Varies by region/season |
| Natural Gas | 1.89 kg COβ/mΒ³ | Standard | Higher for raw gas |
| Water | 0.28 kg COβ/mΒ³ | Treatment & distribution | Pumping + treatment |
| District Cooling | 0.12 kg COβ/kWh | Heat pump efficiency | Lower than direct air conditioning |
| District Heating | 0.08 kg COβ/kWh | Fossil fuel boiler | Varies by fuel mix |
Carbon Calculation Process
Step-by-Step Algorithm:
For Each Meter in System:
Step 1: Retrieve Meter Configuration
ββ Get meter ID and energy category
ββ Get associated emission factor
ββ Get applicable dates for factor changes
Step 2: Determine Reporting Period
ββ Get latest processed carbon timestamp
ββ Calculate time gap since last processing
ββ Fetch energy data for unprocessed period
Step 3: Aggregate Energy Consumption
ββ Sum hourly values by emission factor period
ββ Handle overlapping factors during transitions
ββ Separate by energy subcategory if needed
Step 4: Apply Emission Factors
ββ For each energy block:
β ββ Apply appropriate emission factor
β ββ Calculate COβ equivalent
ββ Sum all blocks for total period carbon
Step 5: Store Carbon Records
ββ Create carbon_ledger entry
ββ Record consumption and COβ equivalent
ββ Mark processed period
ββ Enable future incremental processing
Carbon Metrics:
Primary Metric:
- Scope 1: Direct emissions (on-site fuel combustion)
- Scope 2: Indirect emissions (purchased electricity)
- Scope 3: Other indirect emissions (supply chain, commuting)
Reporting Units:
- kg COβe (kilograms COβ equivalent)
- Tons COβe (metric tons)
- kg COβe per square meter per year
- kg COβe per USD of revenue
Tracking:
- Absolute emissions (total)
- Intensity emissions (per unit)
- Year-over-year trend
- Target progress
Environmental Impact Reporting
Carbon Offset Equivalents:
1 ton COβe equivalent to:
ββ 1.2 acres of forest grown for 10 years
ββ 143 gallons of gasoline burned
ββ 1,025 miles driven in average car
ββ 470 pounds of coal burned
ββ 2,471 kWh electricity consumption
ββ 3.6 barrels of oil consumed
Carbon Reduction Initiatives:
- Track baseline emissions (e.g., first 12 months)
- Compare current vs baseline
- Calculate savings from efficiency projects
- Monitor progress toward carbon neutrality goals
- Generate sustainability reports
Data Processing Pipeline
1. Data Acquisition Service (myems-modbus-tcp)
Architecture:
Modbus TCP Service Architecture:
βββββββββββββββββββββββββββββββββββββββββββββββββββ
β Modbus TCP Acquisition Service β
βββββββββββββββββββββββββββββββββββββββββββββββββββ
β
Main Event Loop
ββ Read configuration from system database
ββ Connect to Modbus gateways
ββ Poll registers at interval (e.g., every 15 min)
ββ Parse Modbus responses
ββ Buffer data in memory
β
Data Buffering & Batching
ββ Accumulate readings in memory
ββ Batch writes to database (e.g., 100 records at once)
ββ Optimize for throughput
β
Historical Database
ββ meter_instantaneous_data (latest value)
ββ meter_hourly_data (aggregated)
ββ Retention: Full precision for 1-2 years
Error Handling:
- Connection Failures: Retry with exponential backoff
- Timeout: Skip reading, try next iteration
- Invalid Data: Log and skip, don't corrupt database
- Database Errors: Backoff and retry
- Meter Reset: Detect via value decrease, calculate actual consumption
2. Data Normalization Service (myems-normalization)
Workflow:
Schedule: Run hourly or on-demand
For Each Meter:
1. Check if normalization needed (new raw data)
2. Retrieve raw values from meter_instantaneous_data
3. Apply normalization formula:
- Raw Γ calibration_factor = normalized value
4. Check for meter resets (current < previous)
5. Calculate incremental consumption:
- If reset: current + (max_value - previous)
- Otherwise: current - previous
6. Store in meter_hourly_data table
7. Update last processed timestamp
For Virtual Meters:
1. Apply formula (e.g., sum of related meters)
2. Calculate based on normalized values
3. Store calculated result
For Data Repair:
1. Detect gaps in time series
2. Use interpolation to fill gaps
3. Validate monotonicity
4. Flag suspicious data
3. Data Cleaning Service (myems-cleaning)
Cleaning Operations:
Schedule: Run daily (typically after peak hours)
Analog Values (e.g., temperature, humidity):
1. Remove outliers (> 3 std dev)
2. Apply smoothing (moving average)
3. Flag suspicious readings
4. Log anomalies for review
Digital Values (binary events):
1. Validate state transitions
2. Remove duplicates
3. Check for impossible sequences
4. Verify timestamp continuity
Energy Values:
1. Ensure monotonicity (never decreases)
2. Detect and flag sudden jumps
3. Remove negative values
4. Handle meter resets properly
5. Check for unrealistic peaks
Duplicate Detection:
1. Identify readings from same meter, same timestamp
2. Keep latest reading
3. Log duplicates for auditing
Historical Data Cleanup:
1. Archive data older than retention period
2. Prune unnecessary detail
3. Generate summary statistics
4. Free up database space
4. Data Aggregation Service (myems-aggregation)
Parallel Processing Architecture:
myems-aggregation Service:
ββ Process 1: Combined Equipment Energy
ββ Process 2: Combined Equipment Billing
ββ Process 3: Combined Equipment Carbon
ββ Process 4: Equipment Energy
ββ Process 5: Equipment Billing
ββ Process 6: Equipment Carbon
ββ Process 7: Meter Billing (all meters)
ββ Process 8: Meter Carbon (all meters)
ββ Process 9: Offline Meter Billing
ββ Process 10: Offline Meter Carbon
ββ Process 11: Virtual Meter Billing
ββ Process 12: Virtual Meter Carbon
ββ Process 13: Space Energy
ββ Process 14: Space Billing
ββ Process 15: Space Carbon
ββ Process 16: Store Energy/Billing/Carbon
ββ Process 17: Tenant Energy/Billing/Carbon
ββ Process 18: Shopfloor Energy/Billing/Carbon
Each Process:
1. Runs independently in separate OS process
2. Loops continuously
3. Queries system database for configuration
4. Processes data incrementally
5. Stores results in respective database
6. Handles errors gracefully with retry logic
7. Logs activity for monitoring
Meter Billing Aggregation Example:
def meter_billing_aggregation():
while True:
try:
# Step 1: Get all meters
meters = query("SELECT * FROM tbl_meters")
for meter in meters:
# Step 2: Get last processed timestamp
last_processed = query(
f"SELECT MAX(end_datetime_utc) FROM "
f"tbl_meter_hourly_billing WHERE meter_id = {meter.id}"
)
# Step 3: Get energy data since last processed
energy_data = query(
f"SELECT * FROM tbl_meter_hourly_data "
f"WHERE meter_id = {meter.id} "
f"AND datetime_utc > {last_processed}"
)
# Step 4: Get applicable tariff
tariff = get_tariff(meter.cost_center_id)
# Step 5: Calculate billing
for hour_data in energy_data:
cost = calculate_cost(hour_data.consumption, tariff)
# Step 6: Store billing record
insert_billing(
meter_id=meter.id,
datetime=hour_data.datetime,
consumption=hour_data.consumption,
cost=cost
)
# Sleep until next cycle (e.g., 1 hour)
time.sleep(3600)
except Exception as e:
logger.error(f"Error in billing aggregation: {e}")
time.sleep(300) # Retry after 5 minutes
Advanced Features
1. Equipment Control & Automation
Supported Equipment Types:
- HVAC systems (heating, cooling, ventilation)
- Lighting systems (on/off, dimming, color)
- Water pumps and valves
- Power switching and load control
- Demand response management
Control Modes:
1. Manual Control
- Operator sends command via UI
- Equipment responds immediately
- Logged for audit trail
2. Scheduled Control
- Predefined schedules (e.g., lights on at 6 AM)
- Recurring patterns (weekdays different from weekends)
- Holiday exceptions
3. Conditional Control (Rules Engine)
- Trigger: If temperature > 28Β°C
- Action: Turn on air conditioning
- Additional conditions: AND time between 9 AM - 5 PM
4. Demand Response
- Participate in utility DR programs
- Automatically reduce load during peak periods
- Maintain comfort while reducing costs
5. Optimization Control (AI)
- Predictive algorithm adjusts setpoints
- Minimizes energy while maintaining comfort
- Learns usage patterns
2. Predictive Analytics & Machine Learning
Prediction Capabilities:
- Energy Consumption Forecast: Predict next day/week/month consumption
- Peak Load Prediction: Anticipate maximum demand
- Anomaly Detection: Identify unusual energy patterns
- Fault Prediction: Detect equipment degradation before failure
- Optimization Recommendations: Suggest energy-saving actions
ML Algorithms Used:
- Time-series forecasting (ARIMA, Prophet)
- Neural networks (LSTM for sequential data)
- Regression models for consumption prediction
- Clustering for pattern identification
- Anomaly detection algorithms
Example Use Case:
Input: Historical consumption data (past 12 months)
Temperature, humidity, occupancy sensors
Historical events (HVAC maintenance)
Model: Trained LSTM neural network
Output: Next 7 days hourly consumption prediction
95% confidence interval
Risk of peak demand > threshold
3. Virtual Power Plants & Microgrids
Virtual Power Plant Capabilities:
- Aggregate distributed energy resources (solar, wind, storage)
- Participate in electricity markets
- Provide grid services (frequency regulation, voltage support)
- Optimize dispatch based on pricing signals
- Manage battery charging/discharging
Microgrid Management:
- Island mode operation (disconnect from main grid)
- Load balancing among local resources
- Forecasting and scheduling
- Economic optimization
- Resilience management
4. Equipment Fault Diagnosis
Fault Detection Methods:
1. Threshold-Based
- Power consumption > threshold = malfunction
- COP (Coefficient of Performance) < expected = degradation
2. Pattern-Based
- Unusual startup/shutdown patterns
- Irregular runtime vs outdoor temperature
- Cycle frequency anomalies
3. Data-Driven
- Neural network trained on normal operation
- Identifies deviations from learned patterns
- Provides confidence score for fault
4. Physics-Based
- Energy balance checks
- Thermodynamic violation detection
- System efficiency metrics
Example - HVAC Fault Detection:
Fault: Refrigerant Leak
Symptoms:
- COP drops from 3.5 to 2.8
- Superheat increases
- Compressor runtime increases 20%
- Discharge temperature rises
Detection:
- Daily COP monitoring
- Alert when 20% below baseline
- Recommend technician visit
- Prevent further degradation
Impact:
- Early detection avoids equipment failure
- Improves efficiency
- Reduces emergency maintenance costs
5. Work Order Management
Workflow:
1. Issue Detection
ββ Automatic via fault diagnosis
ββ Manual report by operator
ββ Scheduled maintenance
2. Work Order Generation
ββ Create ticket
ββ Assign priority and severity
ββ Estimate impact on operations
ββ Route to maintenance team
3. Tracking
ββ Monitor work progress
ββ Track resource usage
ββ Record downtime
ββ Verify completion
4. Verification
ββ Confirm equipment restored
ββ Measure energy impact
ββ Rate technician performance
ββ Archive for trending
5. Analytics
ββ MTBF (Mean Time Between Failures)
ββ MTTR (Mean Time To Repair)
ββ Cost per incident
ββ Technician productivity
ββ Equipment reliability trends
Technical Implementation
1. API Architecture
Falcon Framework Benefits:
Lightweight & Fast:
- Minimal overhead compared to Django/Flask
- Built for microservices
- Excellent performance for data-heavy APIs
Resource-Oriented Design:
- RESTful principles
- Resources = Python classes
- HTTP methods = class methods (on_get, on_post, on_put, on_delete)
Example Resource:
class MeterCollection:
def on_get(self, req, resp):
# GET /v1/meters
# List all meters
def on_post(self, req, resp):
# POST /v1/meters
# Create new meter
class MeterItem:
def on_get(self, req, resp, meter_id):
# GET /v1/meters/{meter_id}
# Retrieve specific meter
def on_put(self, req, resp, meter_id):
# PUT /v1/meters/{meter_id}
# Update meter
def on_delete(self, req, resp, meter_id):
# DELETE /v1/meters/{meter_id}
# Delete meter
API Endpoint Categories:
1. Configuration APIs
/v1/tenants, /v1/buildings, /v1/spaces, /v1/equipment, /v1/meters
2. Data APIs
/v1/meters/{meter_id}/energy/hourly
/v1/spaces/{space_id}/energy/daily
/v1/equipment/{equipment_id}/billing/monthly
3. Report APIs
/v1/reports/meterenergy
/v1/reports/spacebilling
/v1/reports/tenantcarbon
4. Control APIs
/v1/equipment/{equipment_id}/command
/v1/devices/{device_id}/control
5. Analysis APIs
/v1/analytics/prediction/consumption
/v1/analytics/fault-detection
6. Administration APIs
/v1/users, /v1/permissions, /v1/roles
2. Caching Strategy
Multi-Level Caching:
Level 1: Browser Cache
- Static assets (CSS, JS, images)
- Cache duration: 1-7 days
- Reduces network traffic
Level 2: CDN Cache (optional)
- API responses for public data
- Cache duration: 5-30 minutes
- Distributes load globally
Level 3: Redis Application Cache
- Frequently accessed data (meters, buildings)
- List queries with filters
- Cache duration: 5-60 minutes
Example:
meter:list:tenant_id_1 β [list of meters for tenant 1]
meter:item:42 β {meter 42 details}
space:children:10 β [child spaces of space 10]
Level 4: Database Query Optimization
- Proper indexing
- Query optimization
- Materialized views for aggregations
Cache Invalidation:
Event-Based Invalidation:
- When meter updated β clear meter:item:* and meter:list:*
- When building updated β clear related caches
- When tariff updated β clear billing-related caches
Time-Based Expiration:
- Configuration data: 1 hour TTL
- Real-time data: 5-15 minutes TTL
- Historical aggregations: 24+ hours TTL
3. Database Performance Optimization
Indexing Strategy:
Historical Data Table (Very Large):
Primary Key: (meter_id, datetime_utc)
Indexes:
- (meter_id, datetime_utc) - for range queries
- (datetime_utc) - for time-based filtering
- (energy_category_id, datetime_utc) - for category reports
System Configuration Tables (Medium):
Primary Key: (id)
Indexes:
- (tenant_id) - for tenant data isolation
- (space_id) - for space hierarchy
- (equipment_id) - for equipment relationships
Aggregation Tables (Written Frequently):
Primary Key: (meter_id, start_datetime_utc)
Indexes:
- (meter_id, start_datetime_utc) - for incremental processing
- (cost_center_id, start_datetime_utc) - for cost allocation
Query Optimization:
Inefficient: SELECT * FROM tbl_meter_hourly_data
WHERE MONTH(datetime_utc) = 1 AND YEAR(datetime_utc) = 2024
Problem: Function on column prevents index usage
Optimized: SELECT * FROM tbl_meter_hourly_data
WHERE datetime_utc >= '2024-01-01' AND datetime_utc < '2024-02-01'
Benefit: Uses datetime index for fast range scan
Rule: Avoid functions on indexed columns, use range conditions
Partitioning for Time-Series Data:
Partition by Month:
- tbl_meter_hourly_data_2024_01
- tbl_meter_hourly_data_2024_02
- tbl_meter_hourly_data_2024_03
Benefits:
- Faster queries (smaller partition scanned)
- Easier archival (old partitions moved to storage)
- Parallel processing across partitions
API Architecture
Core API Resources
1. Energy Data API
GET /v1/meters/{meter_id}/energy/hourly
Parameters:
- start_datetime_local: ISO format timestamp
- end_datetime_local: ISO format timestamp
- language: en/zh_CN/etc.
Response:
{
"meter_id": 42,
"meter_name": "Building A - Electricity Meter",
"energy_category": "Electricity",
"energy_item": "Consumption (kWh)",
"values": [
{
"datetime": "2024-01-15T00:00:00+08:00",
"value": 123.45,
"previous_value": 120.12
},
...
]
}
2. Billing API
GET /v1/meters/{meter_id}/billing/monthly
Parameters:
- month: YYYY-MM format
- language: en/zh_CN/etc.
Response:
{
"meter_id": 42,
"month": "2024-01",
"consumption": 1500.25,
"unit": "kWh",
"billing_amount": 234.50,
"currency": "USD",
"tariff": "Time-of-Use",
"breakdown": {
"peak_consumption": 800.0,
"peak_cost": 150.00,
"off_peak_consumption": 700.25,
"off_peak_cost": 84.50
}
}
3. Report API
POST /v1/reports/equipment-batch
Body:
{
"equipment_ids": [1, 2, 3],
"start_datetime": "2024-01-01T00:00:00Z",
"end_datetime": "2024-01-31T23:59:59Z",
"report_type": "consumption"
}
Response:
{
"report_id": "abc123",
"status": "generating",
"progress": 45,
"estimated_time": 120,
"download_url": "/v1/reports/abc123/download"
}
4. Control API
POST /v1/equipment/{equipment_id}/command
Body:
{
"command_type": "on/off",
"command_value": "on",
"reason": "Manual control",
"scheduled_time": null
}
Response:
{
"command_id": "cmd_456",
"status": "sent",
"equipment_id": 10,
"timestamp": "2024-01-15T10:30:00Z",
"acknowledgment_time": null
}
Database Design Patterns
Time-Series Data Storage
Challenge: Store billions of energy readings efficiently
Solution Pattern:
1. Raw Data Table (High Frequency)
tbl_meter_instantaneous_data
ββ Columns: meter_id, datetime_utc, value
ββ Retention: Latest 48 hours only
ββ Purpose: Real-time displays
ββ Size: ~100 MB
2. Hourly Aggregation Table (Used for Most Reports)
tbl_meter_hourly_data
ββ Columns: meter_id, datetime_utc, value
ββ Retention: 2-3 years
ββ Purpose: Analysis and reporting
ββ Calculation: SUM/AVG of minutely readings
ββ Size: ~10 GB (much smaller than raw data)
3. Daily Aggregation Table (Trending)
tbl_meter_daily_data
ββ Columns: meter_id, date, value
ββ Retention: 5-10 years
ββ Purpose: Long-term trends
ββ Calculation: SUM of hourly values
ββ Size: ~100 MB
4. Monthly Aggregation Table (Billing & Reports)
tbl_meter_monthly_data
ββ Columns: meter_id, year, month, value
ββ Retention: Permanent (archive)
ββ Purpose: Annual reports, audit
ββ Calculation: SUM of daily values
ββ Size: ~1 MB
Data Lifecycle Management:
Day 1: Minutely data collected (downsampled to hourly)
ββ Hourly: Stored in hourly table
ββ Raw: Kept for 48 hours for detail/verification
Day 2-90: Hourly data used for reports
ββ Available in hourly table
ββ Daily aggregations calculated
Day 91+: Daily data used for trends
ββ Hourly data archived (optional)
ββ Daily table is primary source
Year 2+: Monthly data for archives
ββ Hourly/daily data moved to cold storage
ββ Monthly table in active database
Incremental Aggregation Pattern
Problem: Recalculating aggregations for all historical data is expensive
Solution:
Store "Last Processed Timestamp":
tbl_meter_hourly_billing
ββ Columns:
β ββ meter_id
β ββ start_datetime_utc
β ββ end_datetime_utc β Last processed time
β ββ consumption
β ββ billing_cost
β ββ created_datetime_utc
ββ Index: (meter_id, end_datetime_utc DESC)
Processing Algorithm:
1. Query: SELECT MAX(end_datetime_utc) FROM tbl_meter_hourly_billing
WHERE meter_id = 42
Result: 2024-01-14T23:00:00Z (last processed)
2. Query: SELECT * FROM tbl_meter_hourly_data
WHERE meter_id = 42 AND datetime_utc > 2024-01-14T23:00:00Z
Result: New data since last processing
3. Calculate billing only for new data
4. Insert new records
5. On next cycle, repeat from step 1 (picks up new last_processed time)
Benefit:
- Only processes new data
- O(hours_since_last_process) instead of O(total_hours)
- Scales to any data volume
Hierarchical Data Storage
Challenge: Represent multi-level hierarchy (building β floor β space β equipment)
Solution - Adjacency List with Materialized Path:
Table: tbl_spaces
Standard Adjacency List:
ββ id: 1, name: "Building A", parent_id: NULL
ββ id: 2, name: "Floor 1", parent_id: 1
ββ id: 3, name: "Room 101", parent_id: 2
ββ id: 4, name: "Room 102", parent_id: 2
Problem: Finding all descendants requires recursive query (slow)
Solution - Add Materialized Path:
ββ id: 1, name: "Building A", parent_id: NULL, path: "/1/"
ββ id: 2, name: "Floor 1", parent_id: 1, path: "/1/2/"
ββ id: 3, name: "Room 101", parent_id: 2, path: "/1/2/3/"
ββ id: 4, name: "Room 102", parent_id: 2, path: "/1/2/4/"
Benefits:
- Finding descendants: WHERE path LIKE '/1/2/%' (single query)
- Finding ancestors: path parts between / (single query)
- Building tree: ORDER BY path (natural order)
- Depth = path.split('/').length - 2
Summary: Core Business Logic Flow
Raw Physical Data
β
Modbus TCP Acquisition (myems-modbus-tcp)
ββ Read meters every 15 minutes
ββ Store in meter_instantaneous_data
β
Data Normalization (myems-normalization)
ββ Apply calibration factors
ββ Handle meter resets
ββ Calculate incremental consumption
ββ Store in meter_hourly_data
β
Data Cleaning (myems-cleaning)
ββ Remove outliers
ββ Fill gaps
ββ Validate monotonicity
ββ Clean historical database
β
Data Aggregation (myems-aggregation) - 18 parallel processes
ββ Calculate energy by space/equipment/tenant
ββ Calculate billing with tariff rules
ββ Calculate carbon with emission factors
ββ Store in respective aggregation tables
β
API Service (myems-api) - Handles requests
ββ Query aggregation tables
ββ Cache results in Redis
ββ Generate reports
ββ Serve to Web/Admin UIs
β
User Interfaces
ββ Web UI (React) - Real-time dashboards
ββ Admin UI (AngularJS) - Configuration
ββ Mobile Apps - On-the-go monitoring
Contact & Support
For questions about core logic and advanced features:
- Email: zny@myems.org
- WeChat: +86 13011132526
- QQ Group: 792528967
- GitHub Issues: MyEMS/myems/issues
Document Version: 1.0
Last Updated: January 2025
MyEMS Version: v5.12.0