From 95fcc7f1db19d1b1e01f2d8dbf45d70fbbc725e3 Mon Sep 17 00:00:00 2001 From: pallago <67544460+pallago@users.noreply.github.com> Date: Tue, 5 Nov 2024 22:26:05 +0100 Subject: [PATCH] External sensors (#153) * proof of principle, a DS18B20 is read and its value is transferred via MQTT, also discovery message works * added names for ext sensors * bugfix for names: there was a problem with the topics & added SHT21 support * catch exceptions if a problem during readout occurs, shrink comments in config-file * include ext_sensors in README file * work in progress * bugfix, also for ID of ds18b20 sensor * Revert "bugfix, also for ID of ds18b20 sensor" This reverts commit 1353b840b0b6142670ec59438db4b33fab764b8e. file was intended for another branch * Revert "work in progress" This reverts commit b3e884f79f5356b79f64931cb4d45a150bfce2c7. these changes were intended for another branch * bugfix for ID of ds18b20 sensor --- README.md | 13 +++ ext_sensor_lib/__init__.py | 0 ext_sensor_lib/ds18b20.py | 61 +++++++++++++ ext_sensor_lib/sht21.py | 174 +++++++++++++++++++++++++++++++++++++ src/config.py.example | 6 +- src/rpi-cpu2mqtt.py | 126 ++++++++++++++++++++++++--- 6 files changed, 368 insertions(+), 12 deletions(-) create mode 100644 ext_sensor_lib/__init__.py create mode 100755 ext_sensor_lib/ds18b20.py create mode 100644 ext_sensor_lib/sht21.py diff --git a/README.md b/README.md index 4420880..58e865b 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ The easiest way to track your Raspberry Pi or Ubuntu computer system health and - [Automated](#automated) - [Manual](#manual) - [Configuration](#configuration) + - [External Sensors](#external-sensors) - [Test Raspberry Pi MQTT Monitor](#test-raspberry-pi-mqtt-monitor) - [Schedule Raspberry Pi MQTT Monitor execution as a service](#schedule-raspberry-pi-mqtt-monitor-execution-as-a-service) - [Schedule Raspberry Pi MQTT Monitor execution](#schedule-raspberry-pi-mqtt-monitor-execution) @@ -166,6 +167,18 @@ The group message looks like this: 1.3, 47.1, 12, 1.2, 600, nan, 14.1, 12, 50, -60 ``` +### External Sensors +External sensors (currently DS18B20 for temperature and SHT21 for temperature and humdity) can be read out. +Therefore the ```ext_sensor```key in the config file must be configured. +A list of sensors with properties ```[name, sensor_type, ID, default_value]``` must be given. +The default_value is returned if the Raspberry fails to read the external sensor. The default value is either a scalar or a list, e.g. temperature and humidity. Examples: +* 1x ds18b20 sensor located in the RPi housing: ```ext_sensors = [["Housing", "ds18b20", "0014531448ff", -300]]``` +* If the ID in unkown and if there is only 1 ds18b20 sensor, then use: ```ext_sensors = [["Housing", "ds18b20", 0, -300]]``` +* If there are two sensors, one DS18B20 and one SHT21 (via I2C), then use: ```ext_sensors = [["Housing", "ds18b20", "0014531448ff", -300], ["Outside", "sht21", 0, [-300, 0]]]```, where the -300 is the default value for temperature and 0 is the default value for humidity. + +default option is ```False``` + + ## Test Raspberry Pi MQTT Monitor Run Raspberry Pi MQTT Monitor (this will work only if you used the automated installer or created the shortcut manually) diff --git a/ext_sensor_lib/__init__.py b/ext_sensor_lib/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ext_sensor_lib/ds18b20.py b/ext_sensor_lib/ds18b20.py new file mode 100755 index 0000000..1574cf7 --- /dev/null +++ b/ext_sensor_lib/ds18b20.py @@ -0,0 +1,61 @@ +#!/usr/bin/python3 +import time +import os +""" +This reads the temp value of a DS18B20 sensor +""" + + +def sensor_DS18B20(sensor_id, verbose=False): + """ + :param sensor_id: Name of the sensor id, can be found in /sys/bus/w1/devices + :type sensor_id: string + """ + # read the file + try: + file = open('/sys/bus/w1/devices/28-%s/w1_slave' % sensor_id) + filecontent = file.read() + file.close() + # read temperature value and convert it + stringvalue = filecontent.split("\n")[1].split(" ")[9] + temperature = float(stringvalue[2:]) / 1000 + except IOError as e: + # if an error occurs, we return -300 + temperature = float(-300) + + # format the temperature + temp = '%6.1f' % temperature + temp = round(temperature, 1) + # if we set the verbose, we print the current temperature + if verbose: + print ("1-wire %s: temp=%.1f" % (sensor_id, temp)) + return temp + + +def get_available_sensors(): + """Returns all available sensors""" + # https://github.com/rgbkrk/ds18b20/blob/master/ds18b20/__init__.py + sensors = [] + for sensor in os.listdir("/sys/bus/w1/devices"): + if sensor.startswith("28-"): + # we put all sensor ids into the list (except the "28-" part) + sensors.append(sensor[3:]) + return sensors + + +if __name__ == "__main__": + try: + # call the function to get all sensor_ids as a list + sensors_ids = get_available_sensors() + while True: + for sensor_id in sensors_ids: + sensor_DS18B20(sensor_id=sensor_id, verbose=True) + #sensor_DS18B20("0014531448ff") + time.sleep(2) + except IOError as e: + errno, strerror = e.args + print("I/O error({0}): {1}".format(errno,strerror)) + except KeyboardInterrupt: + print ("keyboard interrupt") + + diff --git a/ext_sensor_lib/sht21.py b/ext_sensor_lib/sht21.py new file mode 100644 index 0000000..4fdd9ec --- /dev/null +++ b/ext_sensor_lib/sht21.py @@ -0,0 +1,174 @@ +#!/usr/bin/python + +""" +from https://raw.githubusercontent.com/kif/sht21_python/refs/heads/python3/sht21.py +from https://github.com/kif/sht21_python/tree/python3 +forked from jaques/sht21_python +with + +The MIT License (MIT) + +Copyright (c) 2013 Richard Jaques + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +""" + + +import fcntl +import time +import unittest + + +class SHT21: + """Class to read temperature and humidity from SHT21, much of class was + derived from: + http://www.sensirion.com/fileadmin/user_upload/customers/sensirion/Dokumente/Humidity/Sensirion_Humidity_SHT21_Datasheet_V3.pdf + and Martin Steppuhn's code from http://www.emsystech.de/raspi-sht21""" + + # control constants + _SOFTRESET = 0xFE + _I2C_ADDRESS = 0x40 + _TRIGGER_TEMPERATURE_NO_HOLD = 0xF3 + _TRIGGER_HUMIDITY_NO_HOLD = 0xF5 + _STATUS_BITS_MASK = 0xFFFC + + # From: /linux/i2c-dev.h + I2C_SLAVE = 0x0703 + I2C_SLAVE_FORCE = 0x0706 + + # datasheet (v4), page 9, table 7, thanks to Martin Milata + # for suggesting the use of these better values + # code copied from https://github.com/mmilata/growd + _TEMPERATURE_WAIT_TIME = 0.086 # (datasheet: typ=66, max=85) + _HUMIDITY_WAIT_TIME = 0.030 # (datasheet: typ=22, max=29) + + def __init__(self, device_number=0): + """Opens the i2c device (assuming that the kernel modules have been + loaded). Note that this has only been tested on first revision + raspberry pi where the device_number = 0, but it should work + where device_number=1""" + self.i2c = open('/dev/i2c-%s' % device_number, 'rb+', 0) + fcntl.ioctl(self.i2c, self.I2C_SLAVE, 0x40) + self.i2c.write(bytes([self._SOFTRESET])) + time.sleep(0.050) + + def read_temperature(self): + """Reads the temperature from the sensor. Not that this call blocks + for ~86ms to allow the sensor to return the data""" + self.i2c.write(bytes([self._TRIGGER_TEMPERATURE_NO_HOLD])) + time.sleep(self._TEMPERATURE_WAIT_TIME) + data = self.i2c.read(3) + if self._calculate_checksum(data, 2) == data[2]: + return self._get_temperature_from_buffer(data) + + def read_humidity(self): + """Reads the humidity from the sensor. Not that this call blocks + for ~30ms to allow the sensor to return the data""" + self.i2c.write(bytes([self._TRIGGER_HUMIDITY_NO_HOLD])) + time.sleep(self._HUMIDITY_WAIT_TIME) + data = self.i2c.read(3) + if self._calculate_checksum(data, 2) == data[2]: + return self._get_humidity_from_buffer(data) + + def close(self): + """Closes the i2c connection""" + self.i2c.close() + + def __enter__(self): + """used to enable python's with statement support""" + return self + + def __exit__(self, type, value, traceback): + """with support""" + self.close() + + @staticmethod + def _calculate_checksum(data, number_of_bytes): + """5.7 CRC Checksum using the polynomial given in the datasheet""" + # CRC + POLYNOMIAL = 0x131 # //P(x)=x^8+x^5+x^4+1 = 100110001 + crc = 0 + # calculates 8-Bit checksum with given polynomial + for byteCtr in range(number_of_bytes): + crc ^= data[byteCtr] + for bit in range(8, 0, -1): + if crc & 0x80: + crc = (crc << 1) ^ POLYNOMIAL + else: + crc = (crc << 1) + return crc + + @staticmethod + def _get_temperature_from_buffer(data): + """This function reads the first two bytes of data and + returns the temperature in C by using the following function: + T = -46.85 + (175.72 * (ST/2^16)) + where ST is the value from the sensor + """ + unadjusted = (data[0] << 8) + data[1] + unadjusted &= SHT21._STATUS_BITS_MASK # zero the status bits + unadjusted *= 175.72 + unadjusted /= 1 << 16 # divide by 2^16 + unadjusted -= 46.85 + return unadjusted + + @staticmethod + def _get_humidity_from_buffer(data): + """This function reads the first two bytes of data and returns + the relative humidity in percent by using the following function: + RH = -6 + (125 * (SRH / 2 ^16)) + where SRH is the value read from the sensor + """ + unadjusted = (data[0] << 8) + data[1] + unadjusted &= SHT21._STATUS_BITS_MASK # zero the status bits + unadjusted *= 125.0 + unadjusted /= 1 << 16 # divide by 2^16 + unadjusted -= 6 + return unadjusted + + +class SHT21Test(unittest.TestCase): + """simple sanity test. Run from the command line with + python -m unittest sht21 to check they are still good""" + + def test_temperature(self): + """Unit test to check the checksum method""" + calc_temp = SHT21._get_temperature_from_buffer([chr(99), chr(172)]) + self.failUnless(abs(calc_temp - 21.5653979492) < 0.1) + + def test_humidity(self): + """Unit test to check the humidity computation using example + from the v4 datasheet""" + calc_temp = SHT21._get_humidity_from_buffer([chr(99), chr(82)]) + self.failUnless(abs(calc_temp - 42.4924) < 0.001) + + def test_checksum(self): + """Unit test to check the checksum method. Uses values read""" + self.failUnless(SHT21._calculate_checksum([chr(99), chr(172)], 2) == 249) + self.failUnless(SHT21._calculate_checksum([chr(99), chr(160)], 2) == 132) + +if __name__ == "__main__": + try: + with SHT21(1) as sht21: + print("Temperature: %s" % sht21.read_temperature()) + print("Humidity: %s" % sht21.read_humidity()) + except IOError as e: + print(type(e), e) + print("Error creating connection to i2c. This must be run as root") + diff --git a/src/config.py.example b/src/config.py.example index 79697ab..e272085 100644 --- a/src/config.py.example +++ b/src/config.py.example @@ -80,4 +80,8 @@ rpi_power_status = False apt_updates = False # Change the thermal zone if you have issues with cpu temps -cpu_thermal_zone = 'cpu' \ No newline at end of file +cpu_thermal_zone = 'cpu' + +# read external sensors for temperature, humidity, pressure etc. +ext_sensors = False +#ext_sensors = [["Housing", "ds18b20", "0014531448ff", -300], ["ext2", "sht21", 0, [-300, 0]]] diff --git a/src/rpi-cpu2mqtt.py b/src/rpi-cpu2mqtt.py index 929ce66..c1705b0 100644 --- a/src/rpi-cpu2mqtt.py +++ b/src/rpi-cpu2mqtt.py @@ -20,6 +20,12 @@ import re import html import uuid import glob +#import external sensor lib only if one uses external sensors +if config.ext_sensors: + # append folder ext_sensor_lib + sys.path.append(os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'ext_sensor_lib'))) + import ds18b20 + from sht21 import SHT21 def check_wifi_signal(format): try: @@ -106,6 +112,46 @@ def check_rpi_power_status(): except Exception as e: return "Error: " + str(e) +def read_ext_sensors(): + """ + here we read the external sensors + we create a list with the external sensors where we append the values + + """ + # we copy the variable from the config file and replace the values by the real sensor values + ext_sensors = config.ext_sensors + # item[0] = name + # item[1] = sensor_type + # item[2] = ID + # item[3] = value + # now we iterate over the external sensors + for item in config.ext_sensors: + # if it is a DS18B20 sensor + if item[1] == "ds18b20": + # if sensor ID in unknown, then we try to get it + # this only works for a single DS18B20 sensor + if item[2]==0: + item[2] = ds18b20.get_available_sensors()[0] + temp = ds18b20.sensor_DS18B20(sensor_id=item[2]) + item[3] = temp + # in case that some error occurs during reading, we get -300 + if temp==-300: + print ("Error while reading sensor %s, %s" % (item[1], item[2])) + if item[1] == "sht21": + try: + with SHT21(1) as sht21: + temp = sht21.read_temperature() + temp = '%2.1f' % temp + hum = sht21.read_humidity() + hum = '%2.1f' % hum + item[3] = [temp, hum] + # in case we have any problems to read the sensor, we continue and keep default values + except Exception: + print ("Error while reading sensor %s" % item[1]) + print (ext_sensors) + return ext_sensors + + def check_cpu_temp(): full_cmd = f"awk '{{printf (\"%.2f\\n\", $1/1000); }}' $(for zone in /sys/class/thermal/thermal_zone*/; do grep -iq \"{config.cpu_thermal_zone}\" \"${{zone}}type\" && echo \"${{zone}}temp\"; done)" @@ -266,7 +312,7 @@ def check_all_drive_temps(): def print_measured_values(cpu_load=0, cpu_temp=0, used_space=0, voltage=0, sys_clock_speed=0, swap=0, memory=0, - uptime_days=0, uptime_seconds=0, wifi_signal=0, wifi_signal_dbm=0, rpi5_fan_speed=0, drive_temps=0, rpi_power_status=0): + uptime_days=0, uptime_seconds=0, wifi_signal=0, wifi_signal_dbm=0, rpi5_fan_speed=0, drive_temps=0, rpi_power_status=0, ext_sensors=[]): remote_version = update.check_git_version_remote(script_dir) output = """:: rpi-mqtt-monitor Version: {} @@ -299,7 +345,8 @@ def print_measured_values(cpu_load=0, cpu_temp=0, used_space=0, voltage=0, sys_c RPI5 Fan Speed: {} RPM RPI Power Status: {} Update: {} - """.format(cpu_load, cpu_temp, used_space, voltage, sys_clock_speed, swap, memory, uptime_days, wifi_signal, wifi_signal_dbm, rpi5_fan_speed, rpi_power_status, check_git_update(script_dir)) + External Sensors: {} + """.format(cpu_load, cpu_temp, used_space, voltage, sys_clock_speed, swap, memory, uptime_days, wifi_signal, wifi_signal_dbm, rpi5_fan_speed, rpi_power_status, check_git_update(script_dir), ext_sensors) drive_temps = check_all_drive_temps() if len(drive_temps) > 0: @@ -495,6 +542,33 @@ def config_json(what_config, device="0"): elif what_config == "apt_updates": data["icon"] = "mdi:update" data["name"] = "APT Updates" + elif what_config == "ds18b20_status": + data["icon"] = "hass:thermometer" + data["name"] = device + " Temperature" + data["unit_of_measurement"] = "°C" + data["device_class"] = "temperature" + data["state_class"] = "measurement" + # we define again the state topic in order to get a unique state topic if we have two sensors of the same type + data["state_topic"] = config.mqtt_topic_prefix + "/" + hostname + "/" + what_config + "_" + device + data["unique_id"] = hostname + "_" + what_config + "_" + device + elif what_config == "sht21_temp_status": + data["icon"] = "hass:thermometer" + data["name"] = device + " Temperature" + data["unit_of_measurement"] = "°C" + data["device_class"] = "temperature" + data["state_class"] = "measurement" + # we define again the state topic in order to get a unique state topic if we have two sensors of the same type + data["state_topic"] = config.mqtt_topic_prefix + "/" + hostname + "/" + what_config + "_" + device + data["unique_id"] = hostname + "_" + what_config + "_" + device + elif what_config == "sht21_hum_status": + data["icon"] = "mdi:water-percent" + data["name"] = device + " Humidity" + data["unit_of_measurement"] = "%" + data["device_class"] = "temperature" + data["state_class"] = "measurement" + # we define again the state topic in order to get a unique state topic if we have two sensors of the same type + data["state_topic"] = config.mqtt_topic_prefix + "/" + hostname + "/" + what_config + "_" + device + data["unique_id"] = hostname + "_" + what_config + "_" + device else: return "" @@ -562,7 +636,7 @@ def publish_update_status_to_mqtt(git_update, apt_updates): def publish_to_mqtt(cpu_load=0, cpu_temp=0, used_space=0, voltage=0, sys_clock_speed=0, swap=0, memory=0, - uptime_days=0, uptime_seconds=0, wifi_signal=0, wifi_signal_dbm=0, rpi5_fan_speed=0, drive_temps=0, rpi_power_status=0): + uptime_days=0, uptime_seconds=0, wifi_signal=0, wifi_signal_dbm=0, rpi5_fan_speed=0, drive_temps=0, rpi_power_status=0, ext_sensors=[]): client = create_mqtt_client() if client is None: return @@ -656,6 +730,34 @@ def publish_to_mqtt(cpu_load=0, cpu_temp=0, used_space=0, voltage=0, sys_clock_s config.mqtt_discovery_prefix + "/sensor/" + config.mqtt_topic_prefix + "/" + hostname + "_rpi_power_status/config", config_json('rpi_power_status'), qos=config.qos) client.publish(config.mqtt_topic_prefix + "/" + hostname + "/rpi_power_status", rpi_power_status, qos=config.qos, retain=config.retain) + if config.ext_sensors: + # we loop through all sensors + for item in ext_sensors: + # item[0] = name + # item[1] = sensor_type + # item[2] = ID + # item[3] = value, like temperature or humidity + if item[1] == "ds18b20": + if config.discovery_messages: + client.publish( + config.mqtt_discovery_prefix + "/sensor/" + config.mqtt_topic_prefix + "/" + hostname + "_" + item[0] + "_status/config", + config_json('ds18b20_status', device=item[0]), qos=config.qos) + client.publish(config.mqtt_topic_prefix + "/" + hostname + "/" + "ds18b20_status_" + item[0], item[3], qos=config.qos, retain=config.retain) + if item[1] == "sht21": + if config.discovery_messages: + # temperature + client.publish( + config.mqtt_discovery_prefix + "/sensor/" + config.mqtt_topic_prefix + "/" + hostname + "_" + item[0] + "_temp_status/config", + config_json('sht21_temp_status', device=item[0]), qos=config.qos) + # humidity + client.publish( + config.mqtt_discovery_prefix + "/sensor/" + config.mqtt_topic_prefix + "/" + hostname + "_" + item[0] + "_hum_status/config", + config_json('sht21_hum_status', device=item[0]), qos=config.qos) + # temperature + client.publish(config.mqtt_topic_prefix + "/" + hostname + "/" + "sht21_temp_status_" + item[0], item[3][0], qos=config.qos, retain=config.retain) + # humidity + client.publish(config.mqtt_topic_prefix + "/" + hostname + "/" + "sht21_hum_status_" + item[0], item[3][1], qos=config.qos, retain=config.retain) + status_sensor_topic = config.mqtt_discovery_prefix + "/sensor/" + config.mqtt_topic_prefix + "/" + hostname + "_status/config" client.publish(status_sensor_topic, config_json('status'), qos=config.qos) @@ -670,10 +772,10 @@ def publish_to_mqtt(cpu_load=0, cpu_temp=0, used_space=0, voltage=0, sys_clock_s def bulk_publish_to_mqtt(cpu_load=0, cpu_temp=0, used_space=0, voltage=0, sys_clock_speed=0, swap=0, memory=0, - uptime_days=0, uptime_seconds=0, wifi_signal=0, wifi_signal_dbm=0, rpi5_fan_speed=0, git_update=0, rpi_power_status="0"): + uptime_days=0, uptime_seconds=0, wifi_signal=0, wifi_signal_dbm=0, rpi5_fan_speed=0, git_update=0, rpi_power_status="0", ext_sensors=[]): # compose the CSV message containing the measured values - values = cpu_load, cpu_temp, used_space, voltage, int(sys_clock_speed), swap, memory, uptime_days, uptime_seconds, wifi_signal, wifi_signal_dbm, rpi5_fan_speed, git_update, rpi_power_status + values = (cpu_load, cpu_temp, used_space, voltage, int(sys_clock_speed), swap, memory, uptime_days, uptime_seconds, wifi_signal, wifi_signal_dbm, rpi5_fan_speed, git_update, rpi_power_status) + tuple(sensor[3] for sensor in ext_sensors) values = str(values)[1:-1] client = create_mqtt_client() @@ -744,7 +846,7 @@ def parse_arguments(): def collect_monitored_values(): - cpu_load = cpu_temp = used_space = voltage = sys_clock_speed = swap = memory = uptime_seconds = uptime_days = wifi_signal = wifi_signal_dbm = rpi5_fan_speed = drive_temps = rpi_power_status = False + cpu_load = cpu_temp = used_space = voltage = sys_clock_speed = swap = memory = uptime_seconds = uptime_days = wifi_signal = wifi_signal_dbm = rpi5_fan_speed = drive_temps = rpi_power_status = ext_sensors = False if config.cpu_load: cpu_load = check_cpu_load() @@ -774,24 +876,26 @@ def collect_monitored_values(): drive_temps = check_all_drive_temps() if config.rpi_power_status: rpi_power_status = check_rpi_power_status() + if config.ext_sensors: + ext_sensors = read_ext_sensors() - return cpu_load, cpu_temp, used_space, voltage, sys_clock_speed, swap, memory, uptime_days, uptime_seconds, wifi_signal, wifi_signal_dbm, rpi5_fan_speed, drive_temps, rpi_power_status + return cpu_load, cpu_temp, used_space, voltage, sys_clock_speed, swap, memory, uptime_days, uptime_seconds, wifi_signal, wifi_signal_dbm, rpi5_fan_speed, drive_temps, rpi_power_status, ext_sensors def gather_and_send_info(): while not stop_event.is_set(): - cpu_load, cpu_temp, used_space, voltage, sys_clock_speed, swap, memory, uptime_days, uptime_seconds, wifi_signal, wifi_signal_dbm, rpi5_fan_speed, drive_temps, rpi_power_status = collect_monitored_values() + cpu_load, cpu_temp, used_space, voltage, sys_clock_speed, swap, memory, uptime_days, uptime_seconds, wifi_signal, wifi_signal_dbm, rpi5_fan_speed, drive_temps, rpi_power_status, ext_sensors= collect_monitored_values() if hasattr(config, 'random_delay'): time.sleep(config.random_delay) if args.display: - print_measured_values(cpu_load, cpu_temp, used_space, voltage, sys_clock_speed, swap, memory, uptime_days, uptime_seconds, wifi_signal, wifi_signal_dbm, rpi5_fan_speed, drive_temps, rpi_power_status) + print_measured_values(cpu_load, cpu_temp, used_space, voltage, sys_clock_speed, swap, memory, uptime_days, uptime_seconds, wifi_signal, wifi_signal_dbm, rpi5_fan_speed, drive_temps, rpi_power_status, ext_sensors) if hasattr(config, 'group_messages') and config.group_messages: - bulk_publish_to_mqtt(cpu_load, cpu_temp, used_space, voltage, sys_clock_speed, swap, memory, uptime_days, uptime_seconds, wifi_signal, wifi_signal_dbm, rpi5_fan_speed, drive_temps, rpi_power_status) + bulk_publish_to_mqtt(cpu_load, cpu_temp, used_space, voltage, sys_clock_speed, swap, memory, uptime_days, uptime_seconds, wifi_signal, wifi_signal_dbm, rpi5_fan_speed, drive_temps, rpi_power_status, ext_sensors) else: - publish_to_mqtt(cpu_load, cpu_temp, used_space, voltage, sys_clock_speed, swap, memory, uptime_days, uptime_seconds, wifi_signal, wifi_signal_dbm, rpi5_fan_speed, drive_temps, rpi_power_status) + publish_to_mqtt(cpu_load, cpu_temp, used_space, voltage, sys_clock_speed, swap, memory, uptime_days, uptime_seconds, wifi_signal, wifi_signal_dbm, rpi5_fan_speed, drive_temps, rpi_power_status, ext_sensors) if not args.service: break