85e8ed9832
this indicates some power issue with the probe(s) and does not really mean that's the temperature. so we don't want the server to send out "high temp" email etc. but rather just a technical error email https://www.controlbyweb.com/support/faq/temp-sensor-reading-error.html
169 lines
5.7 KiB
Python
169 lines
5.7 KiB
Python
# -*- coding: utf-8 -*-
|
|
################################################################################
|
|
#
|
|
# Rattail -- Retail Software Framework
|
|
# Copyright © 2010-2017 Lance Edgar
|
|
#
|
|
# This file is part of Rattail.
|
|
#
|
|
# Rattail is free software: you can redistribute it and/or modify it under the
|
|
# terms of the GNU General Public License as published by the Free Software
|
|
# Foundation, either version 3 of the License, or (at your option) any later
|
|
# version.
|
|
#
|
|
# Rattail is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
# details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License along with
|
|
# Rattail. If not, see <http://www.gnu.org/licenses/>.
|
|
#
|
|
################################################################################
|
|
"""
|
|
TempMon client daemon
|
|
"""
|
|
|
|
from __future__ import unicode_literals, absolute_import
|
|
|
|
import time
|
|
import datetime
|
|
import random
|
|
import socket
|
|
import logging
|
|
|
|
from sqlalchemy.orm.exc import NoResultFound
|
|
|
|
from rattail.daemon import Daemon
|
|
from rattail_tempmon.db import Session, model as tempmon
|
|
from rattail.exceptions import ConfigurationError
|
|
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
class TempmonClient(Daemon):
|
|
"""
|
|
Linux daemon implementation of Tempmon client
|
|
"""
|
|
|
|
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)
|
|
|
|
# figure out which client we are
|
|
hostname = self.config.get('tempmon.client', 'hostname', default=socket.gethostname())
|
|
log.info("i think my hostname is: %s", hostname)
|
|
session = Session()
|
|
try:
|
|
client = session.query(tempmon.Client)\
|
|
.filter_by(hostname=hostname)\
|
|
.one()
|
|
except NoResultFound:
|
|
session.close()
|
|
raise ConfigurationError("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:
|
|
self.take_readings(client_uuid)
|
|
time.sleep(self.delay)
|
|
|
|
def take_readings(self, client_uuid):
|
|
"""
|
|
Take new readings for all enabled probes on this client.
|
|
"""
|
|
session = Session()
|
|
|
|
try:
|
|
client = session.query(tempmon.Client).get(client_uuid)
|
|
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
|
|
try:
|
|
session.commit()
|
|
except:
|
|
log.exception("Failed to read/record temperature data (but will keep trying)")
|
|
session.rollback()
|
|
|
|
finally:
|
|
session.close()
|
|
|
|
def take_reading(self, session, probe):
|
|
"""
|
|
Take a single reading and add to Rattail database.
|
|
"""
|
|
reading = tempmon.Reading()
|
|
reading.degrees_f = self.read_temp(probe)
|
|
|
|
# a reading of 185.0 °F indicates some sort of power issue. when this
|
|
# happens we log an error (which sends basic email) but do not record
|
|
# the temperature. that way the server doesn't see the 185.0 reading
|
|
# and send out a "false alarm" about the temperature being too high.
|
|
# https://www.controlbyweb.com/support/faq/temp-sensor-reading-error.html
|
|
if reading.degrees_f == 185.0:
|
|
log.error("got reading of 185.0 from probe: %s", probe.description)
|
|
|
|
else: # we have a good reading
|
|
reading.client = probe.client
|
|
reading.probe = 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:]
|
|
# temperature data comes in as celsius
|
|
temp_c = float(temp_string) / 1000.0
|
|
# convert celsius to fahrenheit
|
|
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 make_daemon(config, pidfile=None):
|
|
"""
|
|
Returns a tempmon client daemon instance.
|
|
"""
|
|
if not pidfile:
|
|
pidfile = config.get('rattail.tempmon', 'client.pid_path',
|
|
default='/var/run/rattail/tempmon-client.pid')
|
|
return TempmonClient(pidfile, config=config)
|