Hey there!
I’m using Klipper/Mainsail for my AnyCubic Vyper along with a custom built wooden enclosure. My raspberry pi 4B is connected via I2C to DockerPi Sensor Hub, shown here:
The Sensor Hub contains multiple sensors for temperature, humidity, pressure (and some others, not necessary in this case), “hidden” behind a I2C “aggregator”.
So there’s one I2C device with one I2C address containing multiple registers with corresponding values and I’d like to add them separately as sensors.
Any ideas how I can achieve this goal? Tried to customize a own sensor, but right now I couldn’t fully emerse into the kind of code sorcery used.
One first attempt looked this (/home/pi/klipper/klippy/extras/hub.py), I used existing I2C code and tried to make it work:
# HUB(F)/Si7013/Si7020/Si7021/SHT21 i2c based temperature sensors support
#
# Copyright (C) 2020 Lucio Tarantino <lucio.tarantino@gmail.com>
#
# This file may be distributed under the terms of the GNU GPLv3 license.
import logging
from . import bus
HUB_ADDR= 0x17
HUB_COMMANDS = {
'TEMP_REG' :0x01,
'ON_BOARD_TEMP_REG' :0x05,
'ON_BOARD_HUMIDITY_REG' :0x06,
'BMP280_TEMP_REG' :0x08
}
class HUB:
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, default_addr=HUB_ADDR, default_speed=100000)
self.report_time = config.getint('HUB_report_time',30,minval=5)
if self.resolution not in HUB_RESOLUTIONS:
raise config.error("Invalid HUB Resolution. Valid are %s"
% '|'.join(HUB_RESOLUTIONS.keys()))
self.deviceId = config.get('sensor_type')
self.temp = self.min_temp = self.max_temp = self.humidity = 0.
self.sample_timer = self.reactor.register_timer(self._sample_hub)
self.printer.add_object("hub " + self.name, self)
self.printer.register_event_handler("klippy:connect",
self.handle_connect)
def handle_connect(self):
self._init_hub()
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 _init_hub(self):
def _sample_hub(self, eventtime):
try:
params = self.i2c.i2c_read([],3)
response = bytearray(params['response'])
rtemp = response
if self._chekCRC8(rtemp) != response[2]:
logging.warn("HUB: Checksum error on Temperature reading!")
else:
self.temp = (0.002681 * float(rtemp) - 46.85)
logging.debug("HUB: Temperature %.2f " % self.temp)
# Read Humidity
if self.hold_master_mode:
self.i2c.i2c_write([HUB_COMMANDS['HUB_HUMID']])
else:
self.i2c.i2c_write([HUB_COMMANDS['HUB_HUMID_NH']])
# Wait
self.reactor.pause(self.reactor.monotonic()
+ HUB_DEVICES[self.deviceId][self.resolution][1])
params = self.i2c.i2c_read([],3)
response = bytearray(params['response'])
rhumid = response[0] << 8
rhumid|= response[1]
if self._chekCRC8(rhumid) != response[2]:
logging.warn("HUB: Checksum error on Humidity reading!")
else:
#clear status bits,
# humidity always returns xxxxxx10 in the LSB field
rhumid ^= 0x02;
self.humidity = (0.001907 * float(rhumid) - 6)
if (self.humidity < 0):
#due to RH accuracy, measured value might be
# slightly less than 0 or more 100
self.humidity = 0
elif (self.humidity > 100):
self.humidity = 100
# Only for HUB & SHT21.
# Calculates temperature compensated Humidity, %RH
if( self.deviceId in ['SHT21','HUB']
and self.temp > 0 and self.temp < 80):
logging.debug("HUB: Do temp compensation..")
self.humidity = self.humidity
+ (25.0 - self.temp) * HUB_TEMP_COEFFICIENT;
logging.debug("HUB: Humidity %.2f " % self.humidity)
except Exception:
logging.exception("HUB: Error reading data")
self.temp = self.humidity = .0
return self.reactor.NEVER
if self.temp < self.min_temp or self.temp > self.max_temp:
self.printer.invoke_shutdown(
"HUB temperature %0.1f outside range of %0.1f:%.01f"
% (self.temp, self.min_temp, self.max_temp))
measured_time = self.reactor.monotonic()
print_time = self.i2c.get_mcu().estimated_print_time(measured_time)
self._callback(print_time, self.temp)
return measured_time + self.report_time
def get_status(self, eventtime):
return {
'temperature': self.temp,
'humidity': self.humidity,
}
def load_config(config):
# Register sensor
pheater = config.get_printer().lookup_object("heaters")
pheater.add_sensor_factory("HUB", HUB)
But couldn’t get it running