Tapo P110 pump-cycle monitor
A small, private monitor for a domestic waterworks pump connected through a Tapo P110. It reads power locally, records the first and last threshold crossing for every run, and presents the results in a phone-friendly dashboard.
What it records
- Start and stop time for every pump cycle
- Duration, average power, peak power, and estimated energy per cycle
- A rolling 24-hour power trace
- Daily cycle count, total runtime, average duration, and longest duration
- Partial-cycle markers after restarts or communication gaps
- CSV export of completed cycles
With the default two-second polling interval, event times have approximately two-second resolution. Two consecutive readings confirm a transition, but the saved event time is the first threshold crossing.
Run locally with Docker
- Open the local
.envfile in this directory. - Enter
TAPO_USERNAMEandTAPO_PASSWORDusing the account from the Tapo app. - Run
docker compose up --detach --buildfrom this directory. - Open http://localhost:8000.
The dashboard is bound to 127.0.0.1, so it is only available on this computer. Recorded data is stored in a named Docker volume and survives container rebuilds.
Required variables:
| Variable | Value |
|---|---|
TAPO_HOST |
The plug's reserved LAN address, for example 192.168.1.50 |
TAPO_USERNAME |
The email address used for the Tapo account |
TAPO_PASSWORD |
The Tapo account password; keep it only in the ignored local .env file |
DASHBOARD_PASSWORD |
Optional locally; use a long password if the dashboard is ever exposed beyond localhost |
Useful defaults already included in compose.yaml:
| Variable | Default | Meaning |
|---|---|---|
TZ |
Europe/Prague |
Boundary used for daily totals |
POLL_INTERVAL_SECONDS |
2 |
Time between readings |
START_WATTS |
100 |
Two readings at or above this start a cycle |
STOP_WATTS |
30 |
Two readings at or below this stop a cycle |
CONFIRM_SAMPLES |
2 |
Consecutive readings required |
MAX_GAP_SECONDS |
20 |
Longer data gaps split and mark partial cycles |
SAMPLE_RETENTION_DAYS |
30 |
Raw chart history retention; cycle records remain |
DASHBOARD_PORT |
8000 |
Local dashboard port |
DASHBOARD_USERNAME |
water-monitor |
Dashboard login name when a password is configured |
Do not paste real credentials into .env.example, compose.yaml, Git, or application logs. The .env file is excluded by .gitignore and .dockerignore.
Deploy with Coolify and Gitea
Use compose.coolify.yaml for the Coolify deployment. It exposes container port 8000 to Coolify's proxy without publishing a host port and stores SQLite data in the persistent tapo-pump-monitor-data Docker volume.
- Create an application in Coolify from this Gitea repository.
- Select Docker Compose and set the compose file to
/compose.coolify.yaml. - Add
TAPO_HOST,TAPO_USERNAME,TAPO_PASSWORD, andDASHBOARD_PASSWORDas Coolify environment variables. Do not save their real values in Git. - Add a domain in Coolify and route it to the
pump-monitorservice on port 8000. - Deploy and confirm that the service becomes healthy and can reach the plug on the home LAN.
Keep only one instance running. Stop the local Docker deployment at cutover so the same pump cycle is not recorded twice. The local SQLite history can be copied into the Coolify volume before the first server start if it needs to be preserved.
Before starting
- Reserve the plug's LAN address in the router so DHCP does not change it.
- In the Tapo app, enable Me > Third-Party Services > Third-Party Compatibility. Newer P110 firmware otherwise advertises the unsupported TPAP-only local protocol.
- Keep exactly one instance of this service. Multiple instances would record duplicate cycles.
Docker's normal bridge network can initiate connections to devices on the home LAN, so host networking is not required.
Calibrate the thresholds
The defaults are intentionally conservative. After deployment:
- Watch the live wattage while the pump is idle.
- Open a tap and note the stable running wattage.
- Set
START_WATTScomfortably below the running value but above all idle noise. - Set
STOP_WATTSabove idle consumption and belowSTART_WATTS.
For example, if idle is 1 W and the pump is around 750 W, the defaults of 100 W to start and 30 W to stop are suitable.
Useful commands
docker compose up --detach --build # build and start
docker compose ps # show health and port
docker compose logs --follow # watch connection and cycle events
docker compose restart # restart without deleting data
docker compose down # stop; recorded data remains
Do not add --volumes to docker compose down unless you intentionally want to erase all recorded history.
Interpreting likely problems
Once a normal baseline is established, useful warning signals include unusually short repeated cycles, a run much longer than normal, a sharp increase in cycles per hour, or a meaningful change in average running wattage. The dashboard records the evidence first; alert rules can be added after several days of normal data show appropriate limits.