#!/usr/bin/python
# encoding=UTF-8

# Copyright © 2009, 2012 Jakub Wilk <jwilk@jwilk.net>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the “Software”), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

import argparse
import glob
import grp
import os
import pwd
import re
import subprocess
import time

import keyboardleds

def drop_privileges():
    uid = pwd.getpwnam('nobody').pw_uid
    gid = grp.getgrnam('nogroup').gr_gid
    os.setgid(gid)
    os.setuid(uid)

def main(options):
    event_device = glob.glob('/dev/input/by-path/*-event-kbd')[0]
    ledkit = keyboardleds.LedKit(event_device)
    drop_privileges()
    led = getattr(ledkit, options.led.replace('-', '_'))
    temperature_re = re.compile('^ +temp[0-9]+_input: ([0-9.]+)$')
    try:
        while True:
            alert = False
            sensors = subprocess.Popen(['sensors', '-u'], stdout=subprocess.PIPE)
            for line in sensors.stdout:
                line = line.rstrip()
                line = line.decode('ASCII', 'replace') # make Python 3.X happy
                match = temperature_re.match(line)
                if match is not None:
                    temperature = match.group(1)
                    temperature = float(temperature)
                    if options.temperature_limit < temperature < options.bogus_temperature_limit:
                        alert = True
            sensors.wait()
            if alert:
                i = 0
                while i * options.blink_period < options.poll_period:
                    if i & 1 == 0:
                        led.set()
                    else:
                        led.reset()
                    time.sleep(options.blink_period)
                    i += 1
                led.reset()
            else:
                time.sleep(options.poll_period)
    finally:
        led.reset()

def parse_args():
    led_names = list(t + '-lock' for t in ('caps', 'num', 'scroll'))
    class default:
        temperature_limit = 75.0
        bogus_temperature_limit = 200.0
        poll_period = 5.0
        blink_period = 0.2
    ap = argparse.ArgumentParser()
    ap.add_argument('-t', '--temperature-limit', metavar='<temp>', type=float,
        default=default.temperature_limit,
        help='temperatures above this limit will trigger the alert (default: {0:.0f} deg C)'.format(default.temperature_limit),
    )
    ap.add_argument('--bogus-temperature-limit', metavar='<temp>', type=float,
        default=default.bogus_temperature_limit,
        help='temperatures above this limit will be consider bogus, and thus ignored (default: {0:.0f} deg C)'.format(default.bogus_temperature_limit),
    )
    ap.add_argument('--led', choices=led_names, default=led_names[0],
        help='keyboard LED to use',
    )
    ap.add_argument('--poll-period', metavar='<time>', type=float,
        default=default.poll_period,
        help='how often to poll sensors (default: {0:.1f} s)'.format(default.poll_period),
    )
    ap.add_argument('--blink-period', metavar='<time>', type=float,
        default=default.blink_period,
        help='how often to blink when alert is on (default: {0:.1f} s)'.format(default.blink_period),
    )
    return ap.parse_args()

if __name__ == '__main__':
    options = parse_args()
    main(options)

# vim:ts=4 sw=4 et
