Manual troubleshooting tool that pretends to be the Temperature Daemon without reading 1-Wire or GPIO. It publishes the same Redis keys/channels as the real daemon (temp/redis_out.py) so Control, Health, and Web can be tested on a desk or Pi without probes.

What it is / is not

Yes No
Reads control:latest from Redis Reads DS18B20 / sysfs
Publishes temps:latest, temps.reading, temps:setup, health:temps, etc. Drives relays or GPIO
Prints every tick to stdout systemd service (run manually only)
Simulates tub + hot-in dynamics from Control heat state Replaces Control daemon

Important: Stop the real temperature service before running the simulator, or both will fight over temps:latest:

sudo systemctl stop hot-tub-temps

Prerequisites

  • Redis running locally (redis-server)
  • python3-redis (Debian: sudo apt install python3-redis)
  • For realistic behavior: Control daemon publishing control:latest, or inject fake control state yourself (below)

Run

From the repo src directory:

cd /path/to/hot-tub/src
PYTHONPATH=. python3 -m temp_sim

Options:

PYTHONPATH=. python3 -m temp_sim --interval 2
PYTHONPATH=. python3 -m temp_sim --redis-url redis://127.0.0.1:6379/0

Each line on stdout shows mode (HEAT / COOL), Control heat_phase / heat_pump, simulated tub and hot_in °F, and Redis publish status. Ctrl+C to exit.

When finished testing, restart the real daemon if needed:

sudo systemctl start hot-tub-temps

Simulated physics

Starting values: tub average 70 °F, hot-in 70 °F. Step size: 5 °F per interval (default interval 5 s).

Condition Hot-in Tub average (each tick)
Heat-up — heat_phase is startup_1, startup_2, startup_3, or heating, and heat_pump is not off Fixed 130 °F +5 °F (capped at 140 °F)
Cool-down — heat_phase is idle, error_startup, or anything else; or heat_pump is off; or no control:latest Matches current tub −5 °F until floor 70 °F

Four fake tub probes in Redis all equal tub_avg_f; hot probe equals hot_in_f. Setup is always ready with stable fake ROM ids (28-sim-tub1 … 28-sim-hot).

Inject Control state (no Control daemon)

Minimal heating example:

redis-cli SET control:latest '{"heat_phase":"heating","heat_pump":"on","heat_mode":"maintain","target_f":102}'

Cool / idle example:

redis-cli SET control:latest '{"heat_phase":"idle","heat_pump":"off","heat_mode":"sleep","target_f":102}'

Startup attempt (Control checks hot-in rise after ~20 s):

redis-cli SET control:latest '{"heat_phase":"startup_1","heat_pump":"on","heat_mode":"maintain","target_f":102}'

Failed startup:

redis-cli SET control:latest '{"heat_phase":"error_startup","heat_pump":"off","heat_mode":"maintain","target_f":102}'

Run temp_sim in one terminal; change control:latest in another and watch stdout / temps:latest.

Verify Redis output

redis-cli GET temps:latest
redis-cli GET health:temps
redis-cli SUBSCRIBE temps.reading

Health payload includes "detail": "temp_sim (diagnostic simulator)" so you can tell it apart from the real daemon.

Related docs