1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
|
# Support for I2C based LM75/LM75A temperature sensors
#
# Copyright (C) 2020 Boleslaw Ciesielski <combolek@users.noreply.github.com>
#
# This file may be distributed under the terms of the GNU GPLv3 license.
import logging
from . import bus
LM75_CHIP_ADDR = 0x48
LM75_I2C_SPEED = 100000
LM75_REGS = {
"TEMP": 0x00,
"CONF": 0x01,
"THYST": 0x02,
"TOS": 0x03,
"PRODID": 0x07, # TI LM75A chips only?
}
LM75_REPORT_TIME = 0.8
# Temperature can be sampled at any time but the read aborts
# the current conversion. Conversion time is 300ms so make
# sure not to read too often.
LM75_MIN_REPORT_TIME = 0.5
class LM75:
def __init__(self, config):
self.printer = config.get_printer()
self.name = config.get_name().split()[-1]
self.reactor = self.printer.get_reactor()
self.i2c = bus.MCU_I2C_from_config(config, LM75_CHIP_ADDR, LM75_I2C_SPEED)
self.mcu = self.i2c.get_mcu()
self.report_time = config.getfloat(
"lm75_report_time", LM75_REPORT_TIME, minval=LM75_MIN_REPORT_TIME
)
self.temp = self.min_temp = self.max_temp = 0.0
self.sample_timer = self.reactor.register_timer(self._sample_lm75)
self.printer.add_object("lm75 " + self.name, self)
self.printer.register_event_handler("klippy:connect", self.handle_connect)
def handle_connect(self):
self._init_lm75()
self.reactor.update_timer(self.sample_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, cb):
self._callback = cb
def get_report_time_delta(self):
return self.report_time
def degrees_from_sample(self, x):
# The temp sample is encoded in the top 9 bits of a 16-bit
# value. Resolution is 0.5 degrees C.
return x[0] + (x[1] >> 7) * 0.5
def _init_lm75(self):
# Check and report the chip ID but ignore errors since many
# chips don't have it
try:
prodid = self.read_register("PRODID", 1)[0]
logging.info("lm75: Chip ID %#x" % prodid)
except:
pass
def _sample_lm75(self, eventtime):
try:
sample = self.read_register("TEMP", 2)
self.temp = self.degrees_from_sample(sample)
except Exception:
logging.exception("lm75: Error reading data")
self.temp = 0.0
return self.reactor.NEVER
if self.temp < self.min_temp or self.temp > self.max_temp:
self.printer.invoke_shutdown(
"LM75 temperature %0.1f outside range of %0.1f:%.01f"
% (self.temp, self.min_temp, self.max_temp)
)
measured_time = self.reactor.monotonic()
self._callback(self.mcu.estimated_print_time(measured_time), self.temp)
return measured_time + self.report_time
def read_register(self, reg_name, read_len):
# read a single register
regs = [LM75_REGS[reg_name]]
params = self.i2c.i2c_read(regs, read_len)
return bytearray(params["response"])
def write_register(self, reg_name, data):
if type(data) is not list:
data = [data]
reg = LM75_REGS[reg_name]
data.insert(0, reg)
self.i2c.i2c_write(data)
def get_status(self, eventtime):
return {
"temperature": round(self.temp, 2),
}
def load_config(config):
# Register sensor
pheaters = config.get_printer().load_object(config, "heaters")
pheaters.add_sensor_factory("LM75", LM75)
|