diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..b3d698dd73e02f9b13fe28dc1f94a02d8b7218ec --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +*.swp +*.swo +__pycache__ +*.pyc + diff --git a/ssn_temperdaemon.service b/ssn_temperdaemon.service new file mode 100644 index 0000000000000000000000000000000000000000..68a7cdb11b5eeeef393e6cd2ce3cbbc7980c4b4a --- /dev/null +++ b/ssn_temperdaemon.service @@ -0,0 +1,10 @@ +[Unit] +Description=SSN temperature management service +After=network.target + +[Service] +ExecStart=/usr/local/bin/temperature-deamon/temperdaemon.py +Restart=on-failure + +[Install] +WantedBy=multi-user.target diff --git a/temper.py b/temper.py deleted file mode 100755 index 850fd427169b50ebc65e697c7076c5855bbee58d..0000000000000000000000000000000000000000 --- a/temper.py +++ /dev/null @@ -1,116 +0,0 @@ -#!/usr/bin/python -# encoding: utf-8 -# -# Handles devices reporting themselves as USB VID/PID 0C45:7401 (mine also says RDing TEMPerV1.2). -# -# Copyright 2012, 2013 Philipp Adelt <info@philipp.adelt.net> -# -# This code is licensed under the GNU public license (GPL). See LICENSE.md for details. - -# originally from: https://github.com/padelt/temper-python - -# minor updates (calibration, bus/device access) by: -# Maximilian Engelhardt <maxi@stusta.de> -# Johannes Naab <jn@stusta.de> - -import usb -import sys -import struct -import time - -VIDPIDs = [(0x0c45L,0x7401L)] -REQ_INT_LEN = 8 -REQ_BULK_LEN = 8 -TIMEOUT = 2000 - -class TemperDevice(): - def __init__(self, bus, device): - self._device = device - self._bus = bus - self._handle = None - - def get_id(self): - return self._bus.dirname, self._device.filename - - def get_temperature(self, calibration=0, format='celsius'): - try: - if not self._handle: - self._handle = self._device.open() - try: - self._handle.detachKernelDriver(0) - except usb.USBError: - pass - try: - self._handle.detachKernelDriver(1) - except usb.USBError: - pass - self._handle.setConfiguration(1) - self._handle.claimInterface(0) - self._handle.claimInterface(1) - self._handle.controlMsg(requestType=0x21, request=0x09, value=0x0201, index=0x00, buffer="\x01\x01", timeout=TIMEOUT) # ini_control_transfer - - self._control_transfer(self._handle, "\x01\x80\x33\x01\x00\x00\x00\x00") # uTemperatura - self._interrupt_read(self._handle) - self._control_transfer(self._handle, "\x01\x82\x77\x01\x00\x00\x00\x00") # uIni1 - self._interrupt_read(self._handle) - self._control_transfer(self._handle, "\x01\x86\xff\x01\x00\x00\x00\x00") # uIni2 - self._interrupt_read(self._handle) - self._interrupt_read(self._handle) - self._control_transfer(self._handle, "\x01\x80\x33\x01\x00\x00\x00\x00") # uTemperatura - data = self._interrupt_read(self._handle) - data_s = "".join([chr(byte) for byte in data]) - temp_c = (struct.unpack('>h', data_s[2:4])[0]) - temp_c += calibration - temp_c *= 125.0/32000.0 - if format == 'celsius': - return temp_c - elif format == 'fahrenheit': - return temp_c*1.8+32.0 - elif format == 'millicelsius': - return int(temp_c*1000) - else: - raise ValueError("Unknown format") - except usb.USBError, e: - self.close() - if "not permitted" in str(e): - raise Exception("Permission problem accessing USB. Maybe I need to run as root?") - else: - raise - - def close(self): - if self._handle: - try: - self._handle.releaseInterface() - except ValueError: - pass - self._handle = None - - def _control_transfer(self, handle, data): - handle.controlMsg(requestType=0x21, request=0x09, value=0x0200, index=0x01, buffer=data, timeout=TIMEOUT) - - def _interrupt_read(self, handle): - return handle.interruptRead(0x82, REQ_INT_LEN) - - -class TemperHandler(): - def __init__(self): - busses = usb.busses() - # key: (bus.dirname, dev.filename), value: TemperDevice - self._devices = {} - for bus in busses: - for x in bus.devices: - if (x.idVendor,x.idProduct) in VIDPIDs: - tdev = TemperDevice(bus, x) - self._devices[tdev.get_id()] = tdev - - - def get_devices(self): - return self._devices - -if __name__ == '__main__': - th = TemperHandler() - for i, dev in th._devices.iteritems(): - try: - print "Device %s: %0.1f°C %0.1f°F" % (i[0]+"/"+i[1], dev.get_temperature(calibration=0), dev.get_temperature(format="fahrenheit")) - except Exception as e: - print e diff --git a/temperdaemon.py b/temperdaemon.py index e1e8745d5afa6ead89e95fc588ae31f7278bb5c9..50c3e03e879ff95023facc7bf2a8d17fd784f0fd 100755 --- a/temperdaemon.py +++ b/temperdaemon.py @@ -1,13 +1,20 @@ #!/usr/bin/env python2.7 # encoding: utf-8 +# Changelog +# +# 200X Created +# 2017 JW -- Gitted & Updated libtemperusb and changed the interfaces accordingly + + import os import sys +sys.path.append("../temper") os.environ["USB_DEVFS_PATH"] = "/dev/bus/usb/temper" import socket -import temper +from temperusb import temper import threading import time import Queue @@ -18,9 +25,9 @@ from collections import deque, namedtuple from email.mime.text import MIMEText from email.Utils import formatdate -logging.basicConfig(format='%(asctime)s:%(name)s:%(levelname)s:%(message)s', level=logging.DEBUG) +logging.basicConfig(format='%(asctime)s:%(name)s:%(levelname)s:%(message)s', level=logging.INFO) logger = logging.getLogger(__name__) -logger.setLevel(logging.DEBUG) +logger.setLevel(logging.INFO) READINGINTERVAL = 10 @@ -37,6 +44,28 @@ MAX_OUTDOOR_DIFF = 15 MAILINTERVAL = 3600 +# Read the BUS and ADDRESS from a lsusb: +# +# $ lsusb +# ... +# Bus 005 Device 008: ID 0c45:7401 Microdia TEMPer Temperature Sensor +# ... +# +# meaning: use the pair (5, 8) as bus, address tuple. +DEVICEMAPPING_USB = { + #(BUS, ADDRESS): (identifier, calibration) + (5, 8): ("floor", 5.00), + (5, 7): ("ceiling", 3.00), + (1, 4): ("outdoor", 3.30), +} + + +DEVICEMAPPING_SERIAL = [ + ('floorserial', '10.C238A5010800'), + ('ceilserial', '10.0C33A5010800') +] + + SPAM = False #SPAM = True @@ -49,7 +78,7 @@ class TempReader(threading.Thread): self.iteration = 0 def queue_mail(self, floor, ceiling, outdoor): - logger.debug("write mail ...") + logger.info("write mail ...") body = u'''DON'T PANIC! @@ -70,9 +99,9 @@ oo $ $ "$ o$$$$$$$$$ $$$$$$$$$$$$$ $$$$$$$$$o $$$o$$o$ $$$$$$$$$$$$$$$$$$$$$$$ $$$$$$$$$$$$$ $$$$$$$$$$$$$$ """$$$ "$$$""""$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ "$$$ $$$ o$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ "$$$o - o$$" $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ $$$o - $$$ $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$" "$$$$$$ooooo$$$$o - o$$$oooo$$$$$ $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ o$$$$$$$$$$$$$$$$$ + o$$" $$$$$$$$$$$$$$$$$$$$$$$$S$$$$$$$$$$$$$$$$$$$$$$$$$$ $$$o + $$$ $$$$$$$$$$$$$$$$$$$$$$$$SS$$$$$$$$$$$$$$$$$$$" "$$$$$$ooooo$$$$o + o$$$oooo$$$$$ $$$$$$$$$$$$$$$$SSSS$$$$$$$$$$$$$$$$$ o$$$$$$$$$$$$$$$$$ $$$$$$$$"$$$$ $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ $$$$"""""""" """" $$$$ "$$$$$$$$$$$$$$$$$$$$$$$$$$$$" o$$$ "$$$o """$$$$$$$$$$$$$$$$$$"$$" $$$ @@ -96,13 +125,14 @@ oo $ $ "$ o$$$$$$$$$ $$$$$$$$$$$$$ $$$$$$$$$o $$$o$$o$ msg['Subject'] = u"Temperaturalarm Serverraum" msg['From'] = src if SPAM: - dst = ["markus.hefele@stusta.net"] + dst = ["jw@stusta.net"] else: dst = ["admins@stustanet.de"] msg['To'] = ", ".join(dst) msg['Date'] = formatdate(localtime=True) - - #self.mail_queue.put((src, dst, msg.as_string())) + + # Commented out for debugging reasons to not concern the admins + self.mail_queue.put((src, dst, msg.as_string())) def run(self): while True: @@ -112,13 +142,14 @@ oo $ $ "$ o$$$$$$$$$ $$$$$$$$$$$$$ $$$$$$$$$o $$$o$$o$ th = temper.TemperHandler() # TODO naming things is hard! - for i, temp_device in th._devices.iteritems(): - - temp_sensor = temperature_sensors.get(i) + for usb_device in th.get_devices(): + busadress = (usb_device._device.bus, usb_device._device.address) + temp_sensor = temperature_sensors.get(busadress) if temp_sensor: try: - temp_c = temp_device.get_temperature(calibration=temp_sensor.calibration) + usb_device.set_calibration_data(scale=1, offset=temp_sensor.calibration) + temp_c = usb_device.get_temperature() record = temp_sensor.update(temp_c) self.export_queue.put(record) except Exception as e: @@ -190,7 +221,7 @@ oo $ $ "$ o$$$$$$$$$ $$$$$$$$$$$$$ $$$$$$$$$o $$$o$$o$ if (self.iteration > 1 and self.last_mail + 300 < now and (ceiling > CEILING_LIMIT_EMR or floor > FLOOR_LIMIT_EMR)): self.last_mail = now self.queue_mail(floor, ceiling, outdoor) - logger.debug("--------------EMERGENCY------------") + logger.info("--------------EMERGENCY------------") sys.stdout.flush() @@ -220,8 +251,8 @@ class Mail0r(threading.Thread): s.sendmail(sender, recipient, msg) s.quit() except Exception as e: - logger.debug("----ERROR---MAIL----") - logger.debug(e) + logger.error("----ERROR---MAIL----") + logger.error(e) CollectdRecord = namedtuple("CollectdRecord", ["hostname", "path", "interval", "epoch", "value"]) @@ -251,7 +282,7 @@ class Exp0rt0r(threading.Thread): s.setblocking(False) self.socket = s except Exception as e: - logger.debug(e) + logger.error(e) time.sleep(1) continue @@ -312,7 +343,7 @@ class TempSensor(object): self.temperature = temperature self.last_updated = now - logger.debug("update %s", self) + logger.info("update %s", self) return CollectdRecord(HOSTNAME, self._path, int(self._interval), int(self.last_updated), "%f" % (self.temperature,)) @@ -363,16 +394,24 @@ temperature_sensors = {} temperature_sensors_usb_by_name = {} temperature_sensors_serial_by_name = {} -for name, calibration, bus, device in [('floor', 500, '001', '001'), ('ceiling', 300, '002', '001'), ('outdoor', 330, '003', '001')]: - temperature_sensors[(bus, device)] = TempSensorUSB(name, calibration, bus, device) +for busadress, descriptor in DEVICEMAPPING_USB.items(): + temperature_sensors[busadress] = TempSensorUSB( + descriptor[0], + descriptor[1], + busadress[0], + busadress[1]) - temperature_sensors_usb_by_name[name] = temperature_sensors[(bus, device)] + temperature_sensors_usb_by_name[descriptor[0]] = temperature_sensors[busadress] -for name, owid in [('floorserial', '10.C238A5010800'), ('ceilserial', '10.0C33A5010800')]: - temperature_sensors[('serial', owid)] = TempSensorSerial(name, owid) +from pprint import pprint +pprint(temperature_sensors_usb_by_name) +for name, owid in DEVICEMAPPING_SERIAL: + temperature_sensors[('serial', owid)] = TempSensorSerial(name, owid) + temperature_sensors_serial_by_name[name] = temperature_sensors[('serial', owid)] + if __name__ == "__main__": mail_queue = Queue.Queue() export_queue = Queue.Queue()