Add basic tempmon-client command

This commit is contained in:
Lance Edgar 2017-04-01 23:56:57 -05:00
parent c1bfa903db
commit c117f53a82
3 changed files with 166 additions and 23 deletions

View file

139
hotcooler/tempmon/client.py Normal file
View file

@ -0,0 +1,139 @@
"""
Tempmon Client
Responsible for reading temperatures from probes, and recording to database
"""
import sys
import argparse
import time
import datetime
import random
import socket
import logging
from sqlalchemy.orm.exc import NoResultFound
from websauna.system.devop.cmdline import init_websauna
from hotcooler import models
log = logging.getLogger(__name__)
class TempmonClient:
"""
Linux daemon implementation of Tempmon client
"""
# must set this to a sessionmaker
Session = None
def run(self):
"""
This method is invoked upon daemon startup. It is meant to run/loop
"forever" or until daemon stop.
"""
# maybe generate random data instead of reading from true probe
# self.dummy_probes = self.config.getbool('tempmon.client', 'dummy_probes', default=False)
self.dummy_probes = True # TODO
# figure out which client we are
# hostname = self.config.get('tempmon.client', 'hostname', default=socket.gethostname())
hostname = 'demo.rattail-tempmon.org' # TODO
session = self.Session()
try:
client = session.query(models.Client)\
.filter_by(hostname=hostname)\
.one()
except NoResultFound:
session.close()
raise RuntimeError("No tempmon client configured for hostname: {}".format(hostname))
client_uuid = client.uuid
self.delay = client.delay or 60
session.close()
# main loop: take readings, pause, repeat
while True:
session = self.Session()
try:
client = session.query(models.Client).filter_by(uuid=client_uuid).one()
self.delay = client.delay or 60
if client.enabled:
for probe in client.enabled_probes():
self.take_reading(session, probe)
except:
log.exception("Failed to read/record temperature data (but will keep trying)")
session.rollback()
else:
# make sure we show as being online
if not client.online:
client.online = True
session.commit()
finally:
session.close()
time.sleep(self.delay)
def take_reading(self, session, probe):
"""
Take a single reading and add to Rattail database.
"""
reading = models.Reading()
reading.client = probe.client
reading.probe = probe
reading.degrees_f = self.read_temp(probe)
reading.taken = datetime.datetime.utcnow()
session.add(reading)
return reading
def read_temp(self, probe):
"""
Check for good reading, then format temperature to our liking
"""
if self.dummy_probes:
return self.random_temp(probe)
lines = self.read_temp_raw(probe)
while lines[0].strip()[-3:] != 'YES':
time.sleep(0.2)
lines = self.read_temp_raw(probe)
equals_pos = lines[1].find('t=')
if equals_pos != -1:
temp_string = lines[1][equals_pos+2:]
temp_c = float(temp_string) / 1000.0
temp_f = temp_c * 9.0 / 5.0 + 32.0
return round(temp_f,4)
def read_temp_raw(self, probe):
"""
Function that gets the raw temp data
"""
with open(probe.device_path, 'rt') as therm_file:
return therm_file.readlines()
def random_temp(self, probe):
temp = random.uniform(probe.critical_temp_min - 5, probe.critical_temp_max + 5)
return round(temp, 4)
def tempmon_client_command(*args):
"""
Manage the hotcooler tempmon-client daemon
"""
parser = argparse.ArgumentParser(prog='tempmon-client',
description=tempmon_client_command.__doc__.strip())
parser.add_argument('config_uri', help="Path to main config file")
args = parser.parse_args(args or sys.argv[1:])
request = init_websauna(args.config_uri, console_app=True)
session = request.dbsession
client = TempmonClient()
client.Session = request.registry.db_session_maker
client.run()

View file

@ -18,26 +18,27 @@ if len(sys.argv) >= 2:
raise RuntimeError("It is not possible to install this package with setup.py. Use pip to install this package as instructed in Websauna tutorial.") raise RuntimeError("It is not possible to install this package with setup.py. Use pip to install this package as instructed in Websauna tutorial.")
setup(name='hotcooler', setup(
version='0.0', name='hotcooler',
description='hotcooler', version='0.0',
long_description=README + '\n\n' + CHANGES, description='hotcooler',
classifiers=[ long_description=README + '\n\n' + CHANGES,
classifiers=[
"Programming Language :: Python", "Programming Language :: Python",
"Framework :: Pyramid", "Framework :: Pyramid",
"Topic :: Internet :: WWW/HTTP", "Topic :: Internet :: WWW/HTTP",
"Topic :: Internet :: WWW/HTTP :: WSGI :: Application", "Topic :: Internet :: WWW/HTTP :: WSGI :: Application",
], ],
author='', author='',
author_email='', author_email='',
url='', url='',
keywords='web websauna pyramid', keywords='web websauna pyramid',
packages=find_packages(), packages=find_packages(),
include_package_data=True, include_package_data=True,
zip_safe=False, zip_safe=False,
test_suite='hotcooler', test_suite='hotcooler',
install_requires=['websauna'], install_requires=['websauna'],
extras_require={ extras_require={
# Dependencies for running test suite # Dependencies for running test suite
'test': [ 'test': [
"pytest", "pytest",
@ -53,11 +54,14 @@ setup(name='hotcooler',
# Dependencies to make releases # Dependencies to make releases
'dev': ['websauna[dev]'], 'dev': ['websauna[dev]'],
}, },
# Define where this application starts as referred by WSGI web servers entry_points = {
entry_points="""\ 'paste.app_factory': [
[paste.app_factory] 'main = hotcooler:main',
main = hotcooler:main ],
""", 'console_scripts': [
) 'tempmon-client = hotcooler.tempmon.client:tempmon_client_command',
],
},
)