atmospi
atmospi copied to clipboard
W1ThermSensor module
Hi,
What about using my W1Thermsensor python module to support more w1therm temperature sensors? https://github.com/timofurrer/w1thermsensor
Cheers :beers:
Thanks! That might be worth considering! I don't think I'll have time to look into it soon, but if you're inclined to put something together, I would be happy to review pull requests!
I started using W1Thermsensor when my temperature logger developed a hardware problem and I needed test and error handling features not present in measure-ds18b20.py. I replaced measure-ds18b20.py with my own code. Unfortunately this program is no longer compatible with Atmospi as I've had to make a number of fundamental changes in order to meet some of my requirements. I now declare all sensors in a separate file, including HighCharts presentation parameters and no longer use the device table.
Although for reasons stated, I can't turn this into a pull request, I can provide some of the code [or all of it if there's interest].
The code of logger.py, the measure-ds18b20.py replacement:
#!/usr/bin/python
# -*- coding: utf-8 -*-
version = "v1.01"
import sys
import time
import datetime
import logging
import logging.handlers
import argparse
import sqlite3 as lite
from w1thermsensor import W1ThermSensor, W1ThermSensorError, NoSensorFoundError, SensorNotReadyError
from settings import settings
sensors = settings['sensor_definitions'] # pointer to sensor definitions in 'settings'
from sensors import ds18b20
def store_temperatures(sensors, sensor_family, temperatures):
try:
db = lite.connect(settings['db'])
cursor = db.cursor()
# read epoch time as an integer.
timestamp = int(time.time())
# Iterate through the devices.
for i in range(0, len(sensors)):
if sensors[i].connected:
# store the temperatures in the database
id = sensor_family + sensors[i].id # prepend the device family name
t = temperatures[id]
logging.debug("--> %3s %s %6.3f", sensors[i].n, timestamp, t['C'])
cursor.execute("INSERT INTO Temperature (DeviceID, Timestamp, C) VALUES(" + str(sensors[i].n) + ", " + str(timestamp) + ", " + str(t['C']) + ")")
# commit the changes to the database
db.commit()
except lite.Error, e:
if db:
db.rollback()
logging.error("DB ---> %s" % e.args[0])
sys.exit(1)
finally:
if db:
db.close()
def main():
# setup argument parsing
argparser = argparse.ArgumentParser(description='Test program for DS18B20 temperature sensors')
argparser.add_argument('--mode', '-m', default='MONITOR',
help='Mode: {TEST, MONITOR, CRON, LIST}')
argparser.add_argument('--logfile', '-lf', help='Log file:')
argparser.add_argument('--loglevel', '-ll', default='WARNING',
help='Log level: {DEBUG, INFO, WARNING, ERROR, CRITICAL}')
# get command line arguments
cmd_args = argparser.parse_args()
# configure the logger
logger = logging.getLogger()
loglevel = getattr(logging, cmd_args.loglevel.upper(), None)
# get the program mode
mode = cmd_args.mode.upper()
if not isinstance(loglevel, int):
sys.exit('ABORT: unknown log level: %s' % cmd_args.loglevel)
else:
logger.setLevel(loglevel)
if cmd_args.logfile:
handler = logging.handlers.RotatingFileHandler(cmd_args.logfile,
mode='a',
maxBytes=1048576,
backupCount=10,
delay=True)
else:
handler = logging.StreamHandler()
logging_format = '%(asctime)15s %(levelname)5s-%(message)s'
time_stamp_format = '%Y-%m-%d %H:%M:%S'
formatter = logging.Formatter(fmt=logging_format, datefmt=time_stamp_format)
handler.setFormatter(formatter)
logger.addHandler(handler)
logging.debug('ARGUMENTS: %s', cmd_args)
# execute main code
now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
degree = u'\N{DEGREE SIGN}'
degreeCelsius = u'{0}'.format(degree).encode('ISO-8859-1') + "C"
sensor_family = '28-' # prepend '28-' for Atmospi compatibility
sensors = ds18b20['ds18b20'] # get the list of all known DS18B20's from sensors
if mode == "LIST":
print '{:2s} {:13s} {:26s} {:12s} {:15s}'.format(" #", "ID", "NAME", "CALIBRATION", "CONNECTED")
print "------------------------------------------------------------------"
for i in range(0, len(sensors)):
print '{:2} {:13s} {:20s} {:11.3f} {:16}'.format\
(sensors[i].n, sensors[i].id, sensors[i].name, sensors[i].calibration, sensors[i].connected)
print "------------------------------------------------------------------"
sys.exit(0)
loop = True
while loop:
test_set = "" # create an empty set of temperature measurement result indicators
temperatures = {}
# "." = measurement successful
# "x" = sensor not found error
# "!" = sensor not ready error
# sample test_set line: '2015-05-06 12:45:20 ..x....'
# indicating that the 3rd connected sensor was not found; in this case sensor 000005fab05d
for i in range(0, len(sensors)):
if sensors[i].connected:
now = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
try:
sensor = W1ThermSensor(W1ThermSensor.THERM_SENSOR_DS18B20, sensors[i].id) # select a specific sensor
temperature = sensor.get_temperature() + sensors[i].calibration # read the temperature for this sensor
if mode == 'CRON':
temperatures[sensor_family + sensors[i].id] = {'C': temperature}
elif mode == 'TEST':
test_set += "."
elif mode == 'MONITOR':
print '{:20s} {:17s} {:6.3f} {:6.3f}'.format(now, sensors[i].name, temperature, sensors[i].calibration)
except NoSensorFoundError as e:
logging.error("NOTFOUND ---> %s, %s " % (sensors[i].id, sensors[i].name))
test_set += "x"
except SensorNotReadyError as e:
logging.error("NOTREADY ---> %s, %s " % (sensors[i].id, sensors[i].name))
test_set += "!"
if mode == 'CRON':
#print temperatures # placeholder for database insertion
store_temperatures(sensors, sensor_family, temperatures)
elif mode == 'TEST':
print now, test_set # print the measurement set to STDOUT
elif mode == 'MONITOR':
print '----------------------------------------------------'
# check if looping is required
if mode == 'TEST' or mode == 'MONITOR': # infinite loop unless mode == 'CRON'
loop = True
elif mode == 'CRON': # terminate if mode == 'CRON'
loop = False
else:
logging.error("INVALIDMODE ---> '%s'", cmd_args.mode)
sys.exit(1)
if __name__ == '__main__':
main()
}
The settings file:
#!/usr/bin/python
# -*- coding: utf-8 -*-
version = "v1.06"
settings = {
# general global settings
'db': '/home/pi/loggerdev/logger.db', # absolute path to the SQLite database file
'sensor_definitions': 'sensors', # sensor definitions to be used
'range_seconds': 7 * 24 * 3600, # how far into the past should data be loaded (in seconds)?
'precision': 3, # number of digits after the decimal point to be used for database loading
't_unit': 'C', # default temperature unit
# HighCharts presentation parameters
'loading': 'loading...', # text to show when HighCharts is building the graph
'height': 800, # plot height in pixels
'ceiling': 80, # maximum value on Y axis
'backgroundColor': '#FFFFF1', # color of the plot background
'lineType': 'spline', # default line type
'fillOpacity': 0.10, # default opacity of area splines
'zoomType': 'xy', # zoom on both axes supported
'legendLayout': 'horizontal', # horizontal legend below X axis
# HighCharts plotbands
'freezing': [-20, 0, 'rgba(110, 165, 221, 0.8)'],
'non_condensing': [55, 80, '#FFF0D1'],
}
The sensors file:
#!/usr/bin/python
# -*- coding: utf-8 -*-
version = "v1.01"
class TemperatureSensor:
def __init__(self,
n=0,
id="",
name="",
calibration=0.0,
connected=1,
legendIndex=0,
seriesType="spline",
lineColor="rgba(215, 44, 44, 1)"):
self.n = n
self.id = id
self.name = name
self.calibration = calibration
self.connected = connected
self.legendIndex = legendIndex
self.seriesType = seriesType
self.lineColor = lineColor
# declare all known DS18B20 temperature sensors
ds18b20_list = [TemperatureSensor(1, "000005e4d76b", "radiator aanvoer", -0.375, 1, 5, "spline", "rgba(0, 204, 0, 0.3)"),
TemperatureSensor(2, "000005e4f2fd", "radiator retour", -0.125, 1, 6, "areaspline", "rgba(0, 204, 0, 0.3)"),
TemperatureSensor(3, "000005e5f606", "CV retour", -1.375, 1, 2, "spline", "rgba(0, 140, 255, 0.3)"),
TemperatureSensor(4, "000005e65e0c", "---NOT CONNECTED---", 0.0, 0),
TemperatureSensor(5, "000005e77695", "tapwater", -1.375, 1, 7, "spline", "rgba(255, 200, 200, 0.4)"),
TemperatureSensor(6, "000005fab05d", "CV ruimte", 0.063, 1, 9, "spline", "rgba(73, 46, 194, 0.3)"),
TemperatureSensor(7, "000005fab2e0", "vloer aanvoer", 0.188, 1, 3, "spline", "#FF9900"),
TemperatureSensor(8, "000005fab89c", "vloer retour", -0.125, 1, 4, "areaspline", "rgba(250, 187, 0, 0.3)"),
TemperatureSensor(9, "000005fb03d6", "CV aanvoer", -0.750, 1, 1, "spline", "rgba(255, 0, 0, 0.5)"),
TemperatureSensor(10, "000005fb1b38", "---NOT CONNECTED---", 0.0, 0),
TemperatureSensor(11, "0000061be3e2", "buitentemperatuur", 0.078, 1, 11, "spline", "rgba(179, 179, 179, 0.5)")]
ds18b20 = {
# This is the list of declared DS18B20 temperature sensors
'ds18b20': ds18b20_list,
}
This code has allowed me to find the problem in my logger [which turned out to be a faulty Pi] and has been collecting data for a few weeks without any problems.
@timofurrer Any particular reason for closing this? I'm still open to it - just haven't worked on Atmospi in a bit.
It was more an accident than intend.. I'll reopen