temperature_combined: A class that can combine several other temperature sensors (#6230)

Signed-off-by: Michael Jäger <michael@mjaeger.eu>
This commit is contained in:
Michael Jäger 2023-08-01 19:18:03 +02:00 committed by GitHub
parent 039daecb4f
commit 6f7c743615
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 157 additions and 1 deletions

View File

@ -2583,6 +2583,24 @@ serial_no:
# The micro-controller to read from. Must be the host_mcu
```
### Combined temperature sensor
Combined temperature sensor is a virtual temperature sensor based on several other sensors. This sensor can be used with extruders, heater_generic and heater beds.
```
sensor_type: temperature_combined
#sensor_list:
# Must be provided. List of sensors to combine to new "virtual"
# sensor.
# E.g. 'temperature_sensor sensor1,extruder,heater_bed'
#combination_method:
# Must be provided. Combination method used for the sensor.
# Available options are 'max', 'min', 'mean'.
#maximum_deviation:
# Must be provided. Maximum permissible deviation between the sensors
# to combine (e.g. 5 degrees). To disable it, use a large value (e.g. 999.9)
```
## Fans
### [fan]

View File

@ -427,8 +427,9 @@ The following information is available in
[bme280 config_section_name](Config_Reference.md#bmp280bme280bme680-temperature-sensor),
[htu21d config_section_name](Config_Reference.md#htu21d-sensor),
[lm75 config_section_name](Config_Reference.md#lm75-temperature-sensor),
and
[temperature_host config_section_name](Config_Reference.md#host-temperature-sensor)
and
[temperature_combined config_section_name](Config_Reference.md#combined-temperature-sensor)
objects:
- `temperature`: The last read temperature from the sensor.
- `humidity`, `pressure`, `gas`: The last read values from the sensor

View File

@ -0,0 +1,128 @@
# -*- coding: utf-8 -*-
# Support for combination of temperature sensors
#
# Copyright (C) 2023 Michael Jäger <michael@mjaeger.eu>
#
# This file may be distributed under the terms of the GNU GPLv3 license.
REPORT_TIME = 0.300
class PrinterSensorCombined:
def __init__(self, config):
self.printer = config.get_printer()
self.reactor = self.printer.get_reactor()
self.name = config.get_name().split()[-1]
# get sensor names
self.sensor_names = config.getlist('sensor_list')
# get maximum_deviation parameter from config
self.max_deviation = config.getfloat('maximum_deviation', above=0.)
# ensure compatibility with itself
self.sensor = self
# get empty list for sensors, could be any sensor class or a heater
self.sensors = []
# get combination method to handle the different sensor values with
algos = {'min': min, 'max': max, 'mean': mean}
self.apply_mode = config.getchoice('combination_method', algos)
# set default values
self.last_temp = self.min_temp = self.max_temp = 0.0
# add object
self.printer.add_object("temperature_combined " + self.name, self)
# time-controlled sensor update
self.temperature_update_timer = self.reactor.register_timer(
self._temperature_update_event)
self.printer.register_event_handler('klippy:connect',
self._handle_connect)
self.printer.register_event_handler('klippy:ready',
self._handle_ready)
def _handle_connect(self):
for sensor_name in self.sensor_names:
sensor = self.printer.lookup_object(sensor_name)
# check if sensor has get_status function and
# get_status has a 'temperature' value
if (hasattr(sensor, 'get_status') and
'temperature' in sensor.get_status(
self.reactor.monotonic())):
self.sensors.append(sensor)
else:
raise self.printer.config_error(
"'%s' does not report a temperature."
% (sensor_name,))
def _handle_ready(self):
# Start temperature update timer
self.reactor.update_timer(self.temperature_update_timer,
self.reactor.NOW)
def setup_minmax(self, min_temp, max_temp):
self.min_temp = min_temp
self.max_temp = max_temp
def setup_callback(self, temperature_callback):
self.temperature_callback = temperature_callback
def get_report_time_delta(self):
return REPORT_TIME
def update_temp(self, eventtime):
values = []
for sensor in self.sensors:
sensor_status = sensor.get_status(eventtime)
sensor_temperature = sensor_status['temperature']
values.append(sensor_temperature)
# check if values are out of max_deviation range
if (max(values) - min(values)) > self.max_deviation:
self.printer.invoke_shutdown(
"COMBINED SENSOR maximum deviation exceeded limit of %0.1f, "
"max sensor value %0.1f, min sensor value %0.1f."
% (self.max_deviation, max(values), min(values),))
temp = self.apply_mode(values)
if temp:
self.last_temp = temp
def get_temp(self, eventtime):
return self.last_temp, 0.
def get_status(self, eventtime):
return {'temperature': round(self.last_temp, 2),
}
def _temperature_update_event(self, eventtime):
# update sensor value
self.update_temp(eventtime)
# check min / max temp values
if self.last_temp < self.min_temp:
self.printer.invoke_shutdown(
"COMBINED SENSOR temperature %0.1f "
"below minimum temperature of %0.1f."
% (self.last_temp, self.min_temp,))
if self.last_temp > self.max_temp:
self.printer.invoke_shutdown(
"COMBINED SENSOR temperature %0.1f "
"above maximum temperature of %0.1f."
% (self.last_temp, self.max_temp,))
# this is copied from temperature_host to enable time triggered updates
# get mcu and measured / current(?) time
mcu = self.printer.lookup_object('mcu')
measured_time = self.reactor.monotonic()
# convert to print time?! for the callback???
self.temperature_callback(mcu.estimated_print_time(measured_time),
self.last_temp)
# set next update time
return measured_time + REPORT_TIME
def mean(values):
if not values:
return
return sum(values) / len(values)
def load_config(config):
pheaters = config.get_printer().load_object(config, "heaters")
pheaters.add_sensor_factory("temperature_combined", PrinterSensorCombined)

View File

@ -33,6 +33,9 @@
# Load "temperature_mcu" sensor
[temperature_mcu]
# Load "temperature_combined" sensor
[temperature_combined]
########################################
# Default thermistors

View File

@ -137,6 +137,12 @@ sensor_pin: PF5
sensor_type: PT1000
sensor_pin: PK1
[temperature_sensor test_combined]
sensor_type: temperature_combined
sensor_list: temperature_sensor test_PT1000,extruder,heater_bed
combination_method: mean
maximum_deviation: 20.0
[controller_fan test_controller_fan]
pin: PH0