Floor Heating Operating Cost Calculator - Technical Specification
Overview
Section titled “Overview”The WarmlyYours Operating Cost Calculator estimates the daily, monthly, and annual electricity costs for running radiant floor heating systems. The calculator has two implementations:
- Public Calculator - A simplified client-side calculation for quick estimates
- Advanced Calculator - A backend service that accounts for monthly temperature variations and thermostat schedules
1. Public Calculator (Frontend)
Section titled “1. Public Calculator (Frontend)”Location
Section titled “Location”- ViewComponent:
app/components/www/floor_heating_calculator_component.rb - ViewComponent:
app/components/www/snow_melting_calculator_component.rb - Stimulus controller:
app/javascript/controllers/floor_heating_calculator_controller.js - Stimulus controller:
app/javascript/controllers/snow_melting_calculator_controller.js
Formula
Section titled “Formula”Cost (cents/day) = kWh_rate × sqft × (hours / 2.3) × wattage / 1000Variables
Section titled “Variables”| Variable | Description | Default | Source |
|---|---|---|---|
kWh_rate | Electricity rate (cents/kWh) | 12-13¢ | Fetched from /api/v1/locations/by_postal_code/:zip |
sqft | Heated square footage | 35 sq ft | User input |
hours | Daily operating hours | 8 hours | User input (slider) |
wattage | Watts per square foot | 15 W/sq ft | Based on selected heating system |
Duty Cycle Factor
Section titled “Duty Cycle Factor”The divisor 2.3 represents a duty cycle factor, accounting for the fact that floor heating systems cycle on and off rather than running continuously. This equates to approximately 43% runtime (1/2.3 ≈ 0.43).
Wattage by Product
Section titled “Wattage by Product”| Heating System | Watts/sq ft |
|---|---|
| TempZone Flex Roll | 15 |
| TempZone Easy Mat | 15 |
| TempZone Cable (3” spacing) | 14.8 |
| TempZone Cable (4” spacing) | 11.1 |
| TempZone Cable (5” spacing) | 8.9 |
| Environ Flex Roll | 12 |
| Environ Easy Mat | 12 |
| Slab Heat Mat | 20 |
Example Calculation
Section titled “Example Calculation”For a 50 sq ft bathroom with TempZone Flex Roll, 8 hours/day use, at 12¢/kWh:
Cost = 12 × 50 × (8 / 2.3) × 15 / 1000 = 12 × 50 × 3.48 × 15 / 1000 = 31,320 / 1000 = 31.32 cents/day (~$0.31/day)2. Advanced Calculator (Backend)
Section titled “2. Advanced Calculator (Backend)”Location
Section titled “Location”app/services/room_configuration/operating_costs_calculator.rbconfig/initializers/room_configuration_constant.rbapp/models/room_configuration.rb
Overview
Section titled “Overview”The advanced calculator computes monthly costs by:
- Fetching local average monthly temperatures by postal code
- Calculating operating hours based on temperature differential
- Applying weekday/weekend thermostat schedules
- Multiplying by system wattage and electricity rate
Primary Formula
Section titled “Primary Formula”monthly_cost = operating_hours × kilowatts × electricity_rateWhere:
operating_hours = (comfort_hours × comfort_factor) + (economy_hours × economy_factor)Temperature-Based Operating Factor
Section titled “Temperature-Based Operating Factor”The system calculates how much heating is needed based on the temperature differential between desired indoor temperature and actual outdoor temperature:
# Comfort mode factortdiff_comfort = comfort_temp - outdoor_temptdiff_comfort = 0 if tdiff_comfort < 0 # No heating needed if warmer outsidetdiff_comfort = comfort_temp if tdiff_comfort > comfort_temp # Cap at maxfactor_comfort = tdiff_comfort / comfort_temp
# Economy mode factortdiff_economy = economy_temp - outdoor_temptdiff_economy = 0 if tdiff_economy < 0tdiff_economy = economy_temp if tdiff_economy > economy_tempfactor_economy = tdiff_economy / economy_tempInterpretation:
- When outdoor temp equals indoor setpoint → factor = 0 (no heating needed)
- When outdoor temp is very cold → factor approaches 1.0 (maximum heating)
- Linear interpolation between these extremes
Constants
Section titled “Constants”Defined in config/initializers/room_configuration_constant.rb:
module RoomConfigurationConstants AVG_DAYS_PER_MONTH = { week_day: 21.75, week_end_day: 8.69 }
HOURS_OF_OPERATION_PER_DAY = { comfort: { week_day: 9.0, week_end_day: 15.0 }, economy: { week_day: 15.0, week_end_day: 9.0 } }
AVERAGE_HOURS = { avg_num_hrs_per_month: 730.56, avg_num_comfort_hrs_per_month: 332.605, # ~11 hrs/day avg_num_economy_hrs_per_month: 397.955 # ~13 hrs/day }endTemperature Presets
Section titled “Temperature Presets”Defined in app/models/room_configuration.rb:
TEMPERATURE_OPTIONS = [ ['Low', 60.0], # Economy setting ['Average', 68.0], # Comfort setting (default) ['Warm', 72.0], ['Hot', 80.0]]Kilowatt Calculation
Section titled “Kilowatt Calculation”def calculate_total_watts heating_elements.sum { |he| he.quantity * he.item.watts.to_f }end
def calculate_total_kilowatts calculate_total_watts / 1000.0endData Sources
Section titled “Data Sources”| Data | Source | Model |
|---|---|---|
| Average monthly temperatures | By postal code | AverageMonthlyTemperature |
| Electricity rates | By postal code | ElectricityRate |
| Heating element wattage | Product catalog | Item |
Electricity Rate Philosophy (Updated December 2025)
Section titled “Electricity Rate Philosophy (Updated December 2025)”For provinces/states with tiered pricing structures, we use the marginal rate (Tier 2 / Step 2) rather than the blended average. This is because:
- Floor heating is additive consumption - When customers add floor heating, they’re adding NEW load on top of existing usage
- Base usage consumes lower tiers - A household’s existing consumption (lights, appliances, HVAC) typically uses up the cheaper Tier 1 allowance
- Additional heating pays the higher rate - The floor heating electricity is billed at the marginal (higher) rate
Example - Quebec (Hydro-Québec Rate D):
- Tier 1: ~6.9¢/kWh (first 40 kWh/day)
- Tier 2: ~10.7¢/kWh (above 40 kWh/day) ← We use this rate
- Using the blended average (7.8¢) would underestimate heating costs by ~27%
Provinces with tiered pricing:
- Quebec: Tier 2 rate (10.7¢) used instead of blended average
- BC: Step 2 rate (14.08¢) used instead of Step 1 (11.72¢)
- Ontario: Mid-peak TOU rate used as representative for heating load
3. Heat Loss Integration
Section titled “3. Heat Loss Integration”When detailed room information is available, the calculator uses heat loss calculations for more accurate estimates.
Trigger Conditions
Section titled “Trigger Conditions”Heat loss calculation is used when:
allow_heat_loss_calculation?returns truecan_calculate_heat_loss?returns true- Room has an indoor floor type
Heat Loss Factors
Section titled “Heat Loss Factors”The detailed calculation accounts for:
- Room insulation (walls, ceiling, floor)
- Window and door openings (U-values)
- Infiltration/air sealing quality
- Room dimensions and orientation
BTU Conversion
Section titled “BTU Conversion”BTU_PER_HOUR_PER_WATT = 3.4121416Located in app/models/heat_lossable_constants.rb
Monthly kWh from Heat Loss
Section titled “Monthly kWh from Heat Loss”def self.get_monthly_operation_kwh(hl_avg_comfort, hl_avg_economy) monthly_kwh = 0.0 [:week_day, :week_end_day].each do |days_type| { comfort: hl_avg_comfort, economy: hl_avg_economy }.each do |mode, hl| monthly_kwh += AVG_DAYS_PER_MONTH[days_type] * HOURS_OF_OPERATION_PER_DAY[mode][days_type] * (hl / BTU_PER_HOUR_PER_WATT) / 1000.0 end end monthly_kwhend4. API Endpoints
Section titled “4. API Endpoints”Get Electricity Rate by Postal Code
Section titled “Get Electricity Rate by Postal Code”GET /api/v1/locations/by_postal_code/:postal_codeResponse:
{ "status": "ok", "average_rate": 0.12}Get Electricity Rate by Coordinates
Section titled “Get Electricity Rate by Coordinates”GET /api/v1/locations/by_lat_lng/?lat=:latitude&lng=:longitude5. Output Format
Section titled “5. Output Format”Backend Calculator Response
Section titled “Backend Calculator Response”{ status: 'ok', operating_cost_by_month: [jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec], operating_cost_annual: 125.50, operating_cost_by_month_average: 10.46, operating_cost_by_coldest_month: 28.75, message: "assuming default SmartStat settings, yielding average operation of 4.2 hours per day annually, and coldest month operation of 8.1 hours per day, based on average monthly temperatures and electricity rates in your area."}Frontend Display
Section titled “Frontend Display”The frontend converts the cost to display:
- Per day:
${(cost / 100).toFixed(2)} - Per month:
${((cost / 100) * 30).toFixed(2)} - Per year:
${((cost / 100) * 365).toFixed(2)}
6. Quick Reference: Cost Estimation
Section titled “6. Quick Reference: Cost Estimation”Typical Operating Costs
Section titled “Typical Operating Costs”Based on the website copy (app/views/pages/floor-heating.html.erb):
Electric floor heating typically costs $0.07–$0.36 per hour. For a standard bathroom (~40 sq. ft.) running a few hours daily: $17–$29 per month.
Factors Affecting Cost
Section titled “Factors Affecting Cost”- Room size — Larger rooms = higher costs
- Flooring material — Tile/stone transfer heat efficiently; carpet/wood may require more energy
- Daily usage — 2 hours vs 6 hours makes a significant difference
- Electricity rates — Local kWh pricing directly impacts costs
7. File References
Section titled “7. File References”| File | Purpose |
|---|---|
app/components/www/floor_heating_calculator_component.rb | Floor heating calculator ViewComponent |
app/components/www/snow_melting_calculator_component.rb | Snow melting calculator ViewComponent |
app/javascript/controllers/floor_heating_calculator_controller.js | Stimulus controller for floor heating |
app/javascript/controllers/snow_melting_calculator_controller.js | Stimulus controller for snow melting |
app/services/room_configuration/operating_costs_calculator.rb | Backend calculator service |
config/initializers/room_configuration_constant.rb | Constants for hours/days |
app/models/room_configuration.rb | Temperature options, wattage tables |
app/models/heat_lossable_constants.rb | BTU conversion constant |
app/views/pages/floor-heating/cost-calculator.html.erb | Public calculator page |