Guides
How Formulas Work

How Formulas Work

This guide explains the PoolCloud formula engine — how it takes your pool's water readings and calculates exactly which chemicals to add and how much.

What is a Formula?

A formula is a complete recipe for balancing a pool's water chemistry. Each formula is designed for a specific sanitization type (chlorine, salt water, bromine, or minerals) and contains:

  • Readings — what to measure (free chlorine, pH, alkalinity, etc.)
  • Target ranges — the ideal range for each reading
  • Balance order — the sequence in which to adjust chemicals (order matters!)
  • Treatments — the chemicals and actions used to correct each reading
  • Adjusters — special logic that accounts for chemical interactions (e.g. pH and alkalinity affect each other)

Formulas in Detail

Chlorine (chlorine_cal_hypo)

The most common formula, designed for standard chlorine pools using calcium hypochlorite.

Readings: Free Chlorine, Total Chlorine, pH, Total Alkalinity, Cyanuric Acid (CYA), Calcium Hardness

Balance order and treatments:

StepReadingTo Raise (up)To Lower (down)
1pHpH Increaser, Soda AshpH Decreaser, Muriatic Acid
2Total AlkalinityAlkalinity Increaser, Baking SodapH Decreaser, Muriatic Acid
3Free ChlorineChlorine Tablets (default), Chlorine Granules, Liquid ChlorineDrain & Refill
4Cyanuric AcidStabilizerDrain & Refill
5Calcium HardnessHardness IncreaserDrain & Refill
6Combined ChlorineShock

Default target ranges:

ReadingTarget RangeNotes
Free Chlorine (FC)1 – 3 ppmWarning buffer: +2 ppm above max
pH7.2 – 7.8
Total Alkalinity (TA)80 – 150 ppmWarning buffer: +20 above, +10 below
Cyanuric Acid (CYA)30 – 50 ppmWarning buffer: +/- 10 ppm
Calcium Hardness (CH)175 – 225 ppmWarning buffer: +/- 25 ppm. Overridden to 200–275 for plaster/concrete/pebble pools
Combined Chlorine (CC)0 – 0.1 ppmInferred from TC - FC. If high, triggers shock

Adjusters: Shock adjuster (infers combined chlorine from TC - FC), pH/TA adjuster (accounts for cross-effects between pH and alkalinity)


Salt Water (salt)

For pools with a salt chlorine generator (SWG). Similar to the chlorine formula but adds salt monitoring and adjusts CYA targets upward since salt systems need more stabilizer.

Readings: Salt, Free Chlorine, Total Chlorine, pH, Total Alkalinity, Cyanuric Acid (CYA), Calcium Hardness

Balance order and treatments:

StepReadingTo Raise (up)To Lower (down)
1pHpH Increaser, Soda AshpH Decreaser, Muriatic Acid
2Total AlkalinityAlkalinity Increaser, Baking SodapH Decreaser, Muriatic Acid
3Free ChlorineIncrease SWG Output (default), Chlorine Granules, DichlorDrain & Refill
4Cyanuric AcidStabilizerDrain & Refill
5Calcium HardnessHardness IncreaserDrain & Refill
6Combined ChlorineShock
7SaltPool SaltDrain & Refill

Target range overrides (vs. chlorine):

ReadingDefault TargetSalt OverrideReason
Cyanuric Acid (CYA)30 – 50 ppm60 – 80 ppmSalt systems require more CYA to protect chlorine produced by the SWG
Salt2700 – 3500 ppmRequired for the SWG cell to produce chlorine

All other target ranges are the same as the chlorine formula.

Key differences from chlorine:

  • Default chlorine treatment is "Increase SWG Output" (a task, not a chemical) — tells the user to turn up their salt cell dial
  • Dichlor is available as a chlorine substitute instead of liquid chlorine
  • Salt reading added with its own treatment

Bromine (bromine)

For pools and hot tubs that use bromine instead of chlorine as a sanitizer.

Readings: Bromine, pH, Total Alkalinity, Cyanuric Acid (CYA), Calcium Hardness

Balance order and treatments:

StepReadingTo Raise (up)To Lower (down)
1pHpH Increaser, Soda AshpH Decreaser, Muriatic Acid
2Total AlkalinityAlkalinity Increaser, Baking SodapH Decreaser, Muriatic Acid
3BromineBromine GranulesDrain & Refill
4Cyanuric AcidStabilizerDrain & Refill
5Calcium HardnessHardness IncreaserDrain & Refill
6Combined ChlorineShock

Default target ranges:

ReadingTarget Range
Bromine (BRO)3 – 5 ppm
pH7.2 – 7.8
Total Alkalinity (TA)80 – 150 ppm
Cyanuric Acid (CYA)30 – 50 ppm
Calcium Hardness (CH)175 – 225 ppm

Key differences:

  • No Free Chlorine or Total Chlorine readings — uses Bromine reading instead
  • Only one treatment option for raising bromine (no substitutions for bromine up)
  • Adjusters: pH/TA only (no shock adjuster since there's no FC/TC)

Minerals (minerals)

For pools using a mineral sanitization system (like Nature2, Frog, etc.). These systems use minerals as the primary sanitizer and only require trace levels of chlorine as a backup.

Readings: Free Chlorine, Total Chlorine, pH, Total Alkalinity, Cyanuric Acid (CYA), Calcium Hardness

Balance order and treatments:

StepReadingTo Raise (up)To Lower (down)
1pHpH Increaser, Soda AshpH Decreaser, Muriatic Acid
2Total AlkalinityAlkalinity Increaser, Baking SodapH Decreaser, Muriatic Acid
3Free ChlorineChlorine Tablets (default), Chlorine Granules, Liquid ChlorineDrain & Refill
4Cyanuric AcidStabilizerDrain & Refill
5Calcium HardnessHardness IncreaserDrain & Refill
6Combined ChlorineShock

Target range overrides (vs. chlorine):

ReadingDefault TargetMinerals OverrideReason
Free Chlorine (FC)1 – 3 ppm0.5 – 4 ppmMineral systems need less chlorine since minerals do most of the sanitizing

All other target ranges are the same as the chlorine formula.

Key differences from chlorine:

  • Wider and lower FC target range (0.5–4 ppm vs 1–3 ppm)
  • Same treatments and balance order otherwise

All Readings Reference

Every reading the engine understands, with its default configuration:

IDNameShort NameUnitsDefault ValueTest RangeDefault TargetWarning Buffer
fcFree ChlorineFree Chlorineppm40 – 101 – 3+2 above, none below
tcTotal ChlorineTotal Chlorineppm40 – 100 – 0.1
ccCombined ChlorineCombined Chlorineppm00 – 70 – 0.1
phpHpH7.45 – 97.2 – 7.8
taTotal AlkalinityAlkalinityppm1000 – 25080 – 150+20 above, +10 below
cyaStabilizer (CYA)CYAppm400 – 30030 – 50+/- 10
chCalcium HardnessHardnessppm2000 – 1000175 – 225+/- 25
saltSalt LevelSaltppm32000 – 50002700 – 3500
broBromineBromineppm30 – 73 – 5
copperCopperCopperppm10 – 70.4 – 0.7
disoxDissolved OxygenDissolved Oxygenppm10 – 156 – 7

How Warning Buffers Work

Some readings have a warning buffer — a zone just outside the target range where the engine generates a warning instead of a treatment action. This prevents over-treating readings that are only slightly off.

For example, Free Chlorine has a target range of 1–3 ppm and a warning buffer of +2 above. If FC reads 4.5 ppm, it's above the 3 ppm max but within the 5 ppm warning ceiling (3 + 2), so the engine returns a warning rather than telling you to drain the pool.

Wall Type Effects on Targets

For plaster, concrete, and pebble pools, the Calcium Hardness target is automatically raised to 200–275 ppm (from the default 175–225 ppm). These surfaces are more susceptible to etching from low-calcium water.

How Combined Chlorine (CC) is Calculated

Combined chlorine is not measured directly. The engine infers it:

CC = Total Chlorine (TC) − Free Chlorine (FC)

If CC is above the target threshold (0.1 ppm), it means chloramines are present. The engine's shock adjuster creates a delta that triggers a shock treatment to break down the chloramines through breakpoint chlorination.


All Treatments Reference

Chemical Treatments

IDNameTypeConcentrationWait TimeDescription
calc_hypoChlorine GranulesDry Chemical67%15 minPre-dissolve in a bucket of water and pour into pool.
na_hcloLiquid ChlorineLiquid Chemical10%60 minPour slowly in front of a return jet to help it mix.
chlorine_tabletsChlorine TabletsTask100%60 minAdd tablets to your chlorinator or floaters. Adjust dials/knobs as needed.
dichlorDichlorDry Chemical99%15 minAdd directly to the pool.
bromineBromine GranulesDry Chemical100%20 minBroadcast directly over the pool surface in small batches.
soda_ashSoda AshDry Chemical100%20 minBroadcast over pool surface in small batches. Also slightly raises alkalinity.
ph_increaserpH IncreaserDry Chemical100%20 minBroadcast over pool surface in small batches. Also slightly raises alkalinity.
m_acidMuriatic AcidLiquid Chemical31%20 minDilute 10:1 with water in an acid-resistant bucket. Turn off pump, pour around perimeter, then run pump for 5 hours.
sodium_bisulfatepH Decreaser (Dry Acid)Dry Chemical100%20 minBroadcast over pool surface. Brush any that settles on the bottom. Also lowers pH.
baking_sodaBaking SodaDry Chemical100%20 minBroadcast over pool surface in small batches. Also slightly raises pH.
alk_increaserAlkalinity IncreaserDry Chemical100%20 minBroadcast over pool surface in small batches. Also slightly raises pH.
cal_chlorHardness IncreaserDry Chemical100%480 min (8 hrs)Broadcast calcium chloride over pool surface in small batches to avoid cloudy water.
cyaStabilizer (Conditioner)Dry Chemical100%20 minDissolve in a 5-gallon bucket of pool water, pour into skimmer, run pump for several hours.
saltPool SaltDry Chemical100%0 minBroadcast evenly over pool surface. Run pump for 24 hours to dissolve.
shockChlorine ShockDry Chemical100%480 min (8 hrs)Add following manufacturer's directions. Shock at night for best results. Run filter for 8 hours. Retest before swimming.

Task Treatments

These aren't chemicals — they're actions for the pool owner to take.

IDNameWait TimeDescription
swg_upIncrease SWG Output0 minTurn up the dial on your salt chlorine generator cell.
drainDilute Pool0 minPartially drain and refill with fresh water. Retest afterward.
drain_fcDilute Pool (FC)0 minStop adding chlorine and wait for it to lower naturally, or partially drain and refill.
drain_cyaDilute Pool (CYA)0 minStop adding stabilized chlorine (tablets/granules). Partially drain and refill with fresh water using a hose filter.
drain_chDilute Pool (CH)0 minPartially drain and refill with fresh water using a hose filter.

Special Treatments

IDNamePurpose
waitWaitInserted automatically between treatments. The ounces field contains the number of minutes to wait.
warningWarningAttached to readings that are slightly out of range but within the warning buffer.

Substitutions by Formula

Each formula has a default treatment (the first in the list) for each reading direction. You can substitute any of the alternatives.

Chlorine Formula Substitutions

ReadingDirectionDefaultAlternatives
pHRaiseph_increasersoda_ash
pHLowersodium_bisulfatem_acid
Total AlkalinityRaisealk_increaserbaking_soda
Total AlkalinityLowersodium_bisulfatem_acid
Free ChlorineRaisechlorine_tabletscalc_hypo, na_hclo
Free ChlorineLowerdrain_fc
Cyanuric AcidRaisecya
Cyanuric AcidLowerdrain_cya
Calcium HardnessRaisecal_chlor
Calcium HardnessLowerdrain_ch
Combined ChlorineLowershock

Salt Formula Substitutions

ReadingDirectionDefaultAlternatives
pHRaiseph_increasersoda_ash
pHLowersodium_bisulfatem_acid
Total AlkalinityRaisealk_increaserbaking_soda
Total AlkalinityLowersodium_bisulfatem_acid
Free ChlorineRaiseswg_upcalc_hypo, dichlor
Free ChlorineLowerdrain_fc
Cyanuric AcidRaisecya
Cyanuric AcidLowerdrain_cya
Calcium HardnessRaisecal_chlor
Calcium HardnessLowerdrain_ch
Combined ChlorineLowershock
SaltRaisesalt
SaltLowerdrain

Bromine Formula Substitutions

ReadingDirectionDefaultAlternatives
pHRaiseph_increasersoda_ash
pHLowersodium_bisulfatem_acid
Total AlkalinityRaisealk_increaserbaking_soda
Total AlkalinityLowersodium_bisulfatem_acid
BromineRaisebromine
BromineLowerdrain
Cyanuric AcidRaisecya
Cyanuric AcidLowerdrain_cya
Calcium HardnessRaisecal_chlor
Calcium HardnessLowerdrain_ch
Combined ChlorineLowershock

Minerals Formula Substitutions

Same as the Chlorine formula — only the FC target range differs (0.5–4 ppm instead of 1–3 ppm).


How the Calculation Engine Works

When you submit readings to the /api/calculate/ endpoint, the engine runs through these steps:

1. Determine Target Ranges

For each reading, the engine determines the ideal range by checking (in order of priority):

  1. Custom target levels you pass in the request (highest priority)
  2. Formula-level overrides (e.g., salt formula sets CYA to 60–80 ppm, minerals formula sets FC to 0.5–4 ppm)
  3. Wall type adjustments (plaster/concrete/pebble pools get CH target of 200–275 ppm)
  4. Default reading targets (lowest priority)

2. Calculate Deltas

For each reading, the engine compares the current value against the target range:

  • Within target range — no action needed
  • Outside target, within warning buffer — a warning is generated (no chemical treatment)
  • Outside warning buffer — a delta is calculated (distance from the midpoint of the target range)

3. Run Adjusters

Adjusters handle chemical interactions between readings. They run after each reading is evaluated.

Shock Adjuster (chlorine, salt, minerals formulas):

  • Infers combined chlorine: CC = TC − FC
  • If CC exceeds the 0.1 ppm threshold, creates a delta that triggers shock treatment
  • This is why both FC and TC readings are important — the difference tells the engine about chloramine levels

pH / TA Adjuster (all formulas):

  • pH and total alkalinity are chemically linked — raising pH also raises TA, and vice versa
  • The adjuster accounts for these cross-effects so the engine doesn't over-correct

4. Execute Treatments in Balance Order

The engine processes readings in a specific order. For each reading:

  1. Check if there's a delta (positive = too low, need to raise; negative = too high, need to lower)
  2. Select the default treatment, or the substitution if one was provided
  3. Run the treatment's dosing function to calculate the exact amount in ounces based on pool volume and delta
  4. Update all deltas to account for side effects

Why order matters: pH is always balanced first because it affects how effective other chemicals are. Alkalinity is second because it buffers pH. Chlorine/bromine is next for sanitization. CYA and CH come later since they change slowly and don't interact with other chemicals as much.

5. Insert Wait Periods

The engine automatically inserts "Wait" actions between treatments that need circulation time:

TreatmentWait Before Next
Chlorine Granules15 minutes
Dichlor15 minutes
Most dry chemicals20 minutes
Liquid Chlorine60 minutes
Chlorine Tablets60 minutes
Hardness Increaser8 hours
Shock8 hours

Wait actions appear in the response with type: "special" and the ounces field contains the number of minutes to wait.

6. Combine Drain Actions

If multiple readings are dangerously high (e.g., both CYA and calcium hardness), the engine combines their individual drain treatments (drain_cya, drain_ch) into a single "Drain & Refill" action and sorts it to the top. One partial drain fixes multiple problems.

7. Append Warnings

Readings within the warning buffer are appended as warning actions at the end. The ounces field on warnings contains the delta from the target range (negative = below target, positive = above target).


Target Level Overrides

Every reading has a default target range, but you can override them per-request:

{
  "target_levels": [
    { "id": "fc", "min": 3, "max": 5 },
    { "id": "ph", "min": 7.4, "max": 7.6 }
  ]
}

This is useful when:

  • A pool has special requirements (e.g., commercial pools need higher chlorine)
  • A user has customized their ideal ranges
  • A specific wall type or sanitization system calls for different targets

The Pool Object

The pool object tells the engine about the physical pool:

FieldDescriptionImpact
gallonsPool volumeDirectly scales all chemical amounts. A 20,000 gallon pool needs twice as much chemical as a 10,000 gallon pool.
water_typeSanitization methodOne of: chlorine, salt_water, bromine, minerals, copper, ozone, uv. Informational — you select the formula explicitly via formula_id.
wall_typePool surface materialOne of: vinyl, plaster, fiberglass, concrete, pebble. Affects calcium hardness targets — plaster, concrete, and pebble pools need higher CH (200–275 ppm) to prevent surface etching.

Understanding the Response

The response contains an ordered list of actions — the steps the pool owner should follow, in sequence.

Action Types

TypeMeaningounces contains
raiseA reading is too low — add a chemical to increase itAmount of chemical in ounces
lowerA reading is too high — add a chemical to decrease itAmount of chemical in ounces
specialA special action: shocking, draining, or waitingMinutes to wait (for wait actions), or amount (for shock/drain)
warningA reading is slightly out of range but within the warning bufferDelta from ideal (negative = too low, positive = too high)

Treatment Options

Each action includes a treatment_options array listing all available treatments for that reading. The treatment field shows the currently selected one. You can use the IDs from treatment_options as substitutions values in future requests to switch treatments.

Example Response Walkthrough

For a 10,000 gallon chlorine pool with FC=0, pH=7.2, TA=80, CYA=0, CH=0:

  1. Raise FC — Add chlorine tablets (1 oz). Alternatives: chlorine granules, liquid chlorine
  2. Wait — 60 minutes for chlorine to circulate
  3. Raise CYA — Add 52 oz stabilizer to protect chlorine from UV
  4. Wait — 20 minutes
  5. Raise CH — Add 288 oz hardness increaser to prevent surface damage

Each step is a separate action in the actions array, in the order they should be performed.