Add basic tempmon-client command
This commit is contained in:
parent
c1bfa903db
commit
c117f53a82
0
hotcooler/tempmon/__init__.py
Normal file
0
hotcooler/tempmon/__init__.py
Normal file
139
hotcooler/tempmon/client.py
Normal file
139
hotcooler/tempmon/client.py
Normal 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()
|
50
setup.py
50
setup.py
|
@ -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',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
Loading…
Reference in a new issue