Added support for SHTC3 module
This commit is contained in:
185
octoprint_enclosure/SHTC3.py
Normal file
185
octoprint_enclosure/SHTC3.py
Normal file
@@ -0,0 +1,185 @@
|
||||
import sys
|
||||
import time
|
||||
|
||||
from smbus2 import SMBus, i2c_msg
|
||||
|
||||
try:
|
||||
import struct
|
||||
except ImportError:
|
||||
import ustruct as struct
|
||||
|
||||
from crc import CrcCalculator, Configuration
|
||||
width = 8
|
||||
poly = 0x31
|
||||
init_value = 0xFF
|
||||
final_xor_value = 0x00
|
||||
reverse_input = False
|
||||
reverse_output = False
|
||||
configuration = Configuration(width, poly, init_value, final_xor_value, reverse_input, reverse_output)
|
||||
|
||||
use_table = True
|
||||
crc_calculator = CrcCalculator(configuration, use_table)
|
||||
|
||||
|
||||
class SHTC3Exception(Exception):
|
||||
""" Base class for exception """
|
||||
|
||||
|
||||
class SHTC3DeviceNotFound(SHTC3Exception, ValueError):
|
||||
""" Device not found """
|
||||
|
||||
|
||||
class SHTC3ReadError(SHTC3Exception, RuntimeError):
|
||||
""" Read error or CRC mismatch """
|
||||
|
||||
|
||||
CMD_SLEEP = 0xB098
|
||||
CMD_WAKE = 0x3517 # 240µs
|
||||
CMD_RESET = 0x805D # 240µs
|
||||
|
||||
CMD_READ_ID = 0xEFC8
|
||||
|
||||
# Normal sample time 12ms
|
||||
# Low sample time 0.8ms
|
||||
CMD_NORMAL_T = 0x7866
|
||||
CMD_NORMAL_RH = 0x58E0
|
||||
CMD_LOW_T = 0x609C
|
||||
CMD_LOW_RH = 0x401A
|
||||
|
||||
CMD_NORMAL_STRETCH_T = 0x7CA2
|
||||
CMD_NORMAL_STRETCH_RH = 0x5C24
|
||||
CMD_LOW_STRETCH_T = 0x6458
|
||||
CMD_LOW_STRETCH_RH = 0x44DE
|
||||
|
||||
SHTC3_I2CADDR_DEFAULT = 0x70
|
||||
|
||||
|
||||
def send_command(bus, address, cmd):
|
||||
"""Write the command bytes to the bus."""
|
||||
byte_array = cmd.to_bytes(2, 'big')
|
||||
for b in byte_array:
|
||||
bus.write_byte_data(address, 0, b)
|
||||
time.sleep(0.001)
|
||||
|
||||
|
||||
def write_then_read(bus, address, cmd, read_length):
|
||||
"""In a single transaction write a cmd, then read the result."""
|
||||
cmd_bytes = cmd.to_bytes(2, 'big')
|
||||
write = i2c_msg.write(address, cmd_bytes)
|
||||
read = i2c_msg.read(address, read_length)
|
||||
|
||||
bus.i2c_rdwr(write, read)
|
||||
|
||||
return bytearray(read)
|
||||
|
||||
|
||||
def process_crc(bytes_array):
|
||||
"""Assume the last byte in the array is the CRC and check it matches the rest of the message.
|
||||
Return just the message bytes."""
|
||||
crc_byte = bytes_array[-1]
|
||||
bytes_array = bytes_array[:-1]
|
||||
|
||||
if not crc_calculator.verify_checksum(bytes_array, crc_byte):
|
||||
raise RuntimeError('Checksum failed')
|
||||
return bytes_array
|
||||
|
||||
|
||||
def to_relative_humidity(raw_data):
|
||||
"""Convert the linearized 16 bit values into Relative humidity (result in %RH)
|
||||
|
||||
Source: https://sensirion.com/media/documents/643F9C8E/6164081E/Sensirion_Humidity_Sensors_SHTC3_Datasheet.pdf
|
||||
"""
|
||||
return 100.0 * (raw_data / 2 ** 16)
|
||||
|
||||
|
||||
def to_temperature(raw_data):
|
||||
"""Convert the linearized 16 bit values into Temperature (result in °C)
|
||||
|
||||
Source: https://sensirion.com/media/documents/643F9C8E/6164081E/Sensirion_Humidity_Sensors_SHTC3_Datasheet.pdf
|
||||
"""
|
||||
return -45 + 175 * (raw_data / 2 ** 16)
|
||||
|
||||
|
||||
def sample_temperature(bus, address):
|
||||
|
||||
send_command(bus, CMD_RESET)
|
||||
time.sleep(0.001)
|
||||
send_command(bus, CMD_WAKE)
|
||||
time.sleep(0.001)
|
||||
|
||||
try:
|
||||
result = write_then_read(bus, address, CMD_NORMAL_STRETCH_T, 3)
|
||||
raw_temp, crc = struct.unpack(">HI", result)
|
||||
|
||||
if not crc_calculator.verify_checksum(result[:-1], crc):
|
||||
raise SHTC3ReadError('CRC Mismatch')
|
||||
|
||||
return to_temperature(raw_temp)
|
||||
|
||||
finally:
|
||||
send_command(bus, CMD_SLEEP)
|
||||
|
||||
|
||||
def sample_humidity(bus, address):
|
||||
send_command(bus, address, CMD_RESET)
|
||||
time.sleep(0.001)
|
||||
send_command(bus, address, CMD_WAKE)
|
||||
time.sleep(0.001)
|
||||
|
||||
try:
|
||||
result = write_then_read(bus, address, CMD_NORMAL_STRETCH_RH, 3)
|
||||
raw_rh, crc = struct.unpack(">HI", result)
|
||||
|
||||
if not crc_calculator.verify_checksum(result[:-1], crc):
|
||||
raise SHTC3ReadError('CRC Mismatch')
|
||||
|
||||
return to_relative_humidity(raw_rh)
|
||||
|
||||
finally:
|
||||
send_command(bus, address, CMD_SLEEP)
|
||||
|
||||
|
||||
def sample_both(bus, address):
|
||||
"""Sample of temperature and humidity."""
|
||||
|
||||
send_command(bus, address, CMD_RESET)
|
||||
send_command(bus, address, CMD_WAKE)
|
||||
|
||||
try:
|
||||
result = write_then_read(bus, address, CMD_NORMAL_STRETCH_T, 6)
|
||||
|
||||
raw_temp, crc_temp, raw_rh, crc_rh = struct.unpack(">HI>HI", result)
|
||||
|
||||
if not crc_calculator.verify_checksum(result[0:2], crc_temp):
|
||||
raise SHTC3ReadError('CRC Mismatch')
|
||||
|
||||
if not crc_calculator.verify_checksum(result[3:5], raw_rh):
|
||||
raise SHTC3ReadError('CRC Mismatch')
|
||||
|
||||
temperature = to_temperature(raw_temp)
|
||||
humidity = to_relative_humidity(raw_rh)
|
||||
|
||||
return temperature, humidity
|
||||
|
||||
finally:
|
||||
# Sleep
|
||||
send_command(bus, address, CMD_SLEEP)
|
||||
|
||||
|
||||
def main():
|
||||
# get i2c bus and bus address if provided or use defaults
|
||||
address = SHTC3_I2CADDR_DEFAULT
|
||||
bus = SMBus(1)
|
||||
if len(sys.argv) > 1:
|
||||
bus = SMBus(int(sys.argv[1]))
|
||||
address = int(sys.argv[2], 16)
|
||||
|
||||
try:
|
||||
temperature, humidity = sample_both(bus, address)
|
||||
print('{0:0.1f} | {1:0.1f}'.format(temperature, humidity))
|
||||
except Exception:
|
||||
print('-1 | -1')
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1045,6 +1045,9 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP
|
||||
elif sensor['temp_sensor_type'] == "hum_raw_i2c":
|
||||
hum, temp = self.read_raw_i2c_temp(sensor)
|
||||
airquality = 0
|
||||
elif sensor['temp_sensor_type'] == "shtc3":
|
||||
temp, hum = self.read_shtc3_temp(sensor['temp_sensor_address'], sensor['temp_sensor_i2cbus'])
|
||||
airquality = 0
|
||||
else:
|
||||
self._logger.info("temp_sensor_type no match")
|
||||
temp = None
|
||||
@@ -1137,6 +1140,24 @@ class EnclosurePlugin(octoprint.plugin.StartupPlugin, octoprint.plugin.TemplateP
|
||||
self.log_error(ex)
|
||||
return 0
|
||||
|
||||
def read_shtc3_temp(self, address, i2cbus):
|
||||
try:
|
||||
script = os.path.dirname(os.path.realpath(__file__)) + "/SHTC3.py"
|
||||
args = ["python", script, str(i2cbus), str(address)]
|
||||
if self._settings.get(["debug_temperature_log"]) is True:
|
||||
self._logger.debug("Temperature SHTC3 cmd: %s", " ".join(args))
|
||||
proc = Popen(args, stdout=PIPE)
|
||||
stdout, _ = proc.communicate()
|
||||
if self._settings.get(["debug_temperature_log"]) is True:
|
||||
self._logger.debug("SHTC3 result: %s", stdout)
|
||||
temp, hum = stdout.decode("utf-8").split("|")
|
||||
return self.to_float(temp.strip()), self.to_float(hum.strip())
|
||||
|
||||
except Exception as ex:
|
||||
self._logger.info("Failed to execute python scripts, try disabling use SUDO on advanced section.")
|
||||
self.log_error(ex)
|
||||
return 0, 0
|
||||
|
||||
def read_dht_temp(self, sensor, pin):
|
||||
try:
|
||||
script = os.path.dirname(os.path.realpath(__file__)) + "/getDHTTemp.py "
|
||||
|
||||
@@ -617,6 +617,7 @@
|
||||
<option value="max31855">MAX31855</option>
|
||||
<option value="rpi">Raspberry Pi CPU</option>
|
||||
<option value="mcp9808">MCP9808</option>
|
||||
<option value="shtc3">SHTC3</option>
|
||||
<option value="temp_raw_i2c">Raw I2C Temperature</option>
|
||||
<option value="hum_raw_i2c">Raw I2C Humidity</option>
|
||||
</select>
|
||||
@@ -682,7 +683,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- /ko -->
|
||||
<!-- ko if: ($data.temp_sensor_type() == "si7021") || ($data.temp_sensor_type() == "20") || ($data.temp_sensor_type() == "bme280") || ($data.temp_sensor_type() == "am2320") || ($data.temp_sensor_type() == "aht10") || ($data.temp_sensor_type() == "tmp102") || ($data.temp_sensor_type() == "mcp9808") -->
|
||||
<!-- ko if: ($data.temp_sensor_type() == "si7021") || ($data.temp_sensor_type() == "20") || ($data.temp_sensor_type() == "bme280") || ($data.temp_sensor_type() == "am2320") || ($data.temp_sensor_type() == "aht10") || ($data.temp_sensor_type() == "tmp102") || ($data.temp_sensor_type() == "mcp9808" || ($data.temp_sensor_type() == "shtc3") -->
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="settings-enclosure-dhtPin">{{ _('Sensor Pin') }}</label>
|
||||
<div class="controls">
|
||||
@@ -732,7 +733,7 @@
|
||||
</div>
|
||||
|
||||
<!-- /ko -->
|
||||
<!-- ko ifnot: ($data.temp_sensor_type() == "rpi") || ($data.temp_sensor_type() == "18b20") || ($data.temp_sensor_type() == "si7021") || ($data.temp_sensor_type() == "bme280") || ($data.temp_sensor_type() == "am2320") || ($data.temp_sensor_type() == "tmp102") || ($data.temp_sensor_type() == "max31855") || ($data.temp_sensor_type() == "mcp9808") || ($data.temp_sensor_type() == "temp_raw_i2c") || ($data.temp_sensor_type() == "hum_raw_i2c") -->
|
||||
<!-- ko ifnot: ($data.temp_sensor_type() == "rpi") || ($data.temp_sensor_type() == "18b20") || ($data.temp_sensor_type() == "si7021") || ($data.temp_sensor_type() == "bme280") || ($data.temp_sensor_type() == "am2320") || ($data.temp_sensor_type() == "tmp102") || ($data.temp_sensor_type() == "max31855") || ($data.temp_sensor_type() == "mcp9808") || ($data.temp_sensor_type() == "shtc3") || ($data.temp_sensor_type() == "temp_raw_i2c") || ($data.temp_sensor_type() == "hum_raw_i2c") -->
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="settings-enclosure-dhtPin">{{ _('Sensor Pin') }}</label>
|
||||
<div class="controls">
|
||||
|
||||
Reference in New Issue
Block a user