#!/usr/bin/env python
#
# generate some heat!
#
# Wrap your RasPi in bubble wrap.  Then run ntpheat in the background.
# It will try to stabilize the CPU temperature at 65C by default.

# Sometimes one copy of ntpheat can use 100% of one CPU and
# still not heat up your RasPi as much as you want.  The temptation
# is to add more insulation to your RasPi, but then it will overshoot
# your target temperature if your load factor goes high.
#
# The solution is to run more than one copy of ntpheat.  This is
# easy to do with the -c option.
#
# To run 3 copies of ntpheat: ntpheat -c 3

import argparse
import hashlib
import os
import sys
import time

try:
    import ntp.util
except ImportError as e:
    sys.stderr.write("ntpheat: can't find Python NTP modules. "
                     "-- check PYTHONPATH.\n%s\n" % e)
    sys.exit(1)

# Work with argvars
parser = argparse.ArgumentParser(description="make heat")
parser.add_argument('-c', '--copies',
                    default=[1],
                    dest='copies',
                    help="Number of copies to run.  Default is 1",
                    nargs=1,
                    type=int)
parser.add_argument('-t', '--temp',
                    default=[65.0],
                    dest='target_temp',
                    help="Temperature to hold.  Default is 65.0",
                    nargs=1,
                    type=float)
parser.add_argument('-w', '--wait',
                    default=[0.001],
                    dest='wait',
                    help="Set delay time in seconds, default is 0.1",
                    nargs=1,
                    type=float)
parser.add_argument('-V', '--version',
                    action="version",
                    version="ntpheat %s" % ntp.util.stdversion())
args = parser.parse_args()

args.copies[0] -= 1
while args.copies[0]:
    args.copies[0] -= 1
    pid = os.fork()
    if pid:
        # I am the fork
        break

zone0 = '/sys/class/thermal/thermal_zone0/temp'
cnt = 0

m = hashlib.md5()
temp = 0
max_cnt = args.wait[0] * 200000
# on a RasPi 3 the temp steps seem to be about 0.537 to 0.539C
temp_gate = args.target_temp[0]

while True:
    # on a RasPi 3, 200,000 of the m.update() can be one second
    delta = temp_gate - temp
    if 0 < delta:
        # heat it up
        m.update("Nobody inspects the spammish repetition")
    else:
        cnt = max_cnt
        # cools off slower than it heats up.
        # undocumented Python 'feature', no sleep less than 1 milli Sec
        sleep = args.wait[0] * 10.0 * -delta
        if 0.001 > sleep:
            sleep = 0.001
        time.sleep(sleep)

    cnt += 1
    # read the temperature every max_cnt
    if max_cnt < cnt:
        cnt = 0

        zone_data = open(zone0, 'r')
        for line in zone_data:
            temp = float(line) / 1000

        zone_data.close()
