from ..base import TemperatureSensor
from ....utility.file_io import search_in_path
import re
import logging
log = logging.getLogger(__name__)
from subprocess import Popen, PIPE
from ctypes import windll
[docs]
class ClewareHumidity(TemperatureSensor):
"""
Support for a Cleware USB-Humidity Sensor
The executable communicating with the device, USBSwitchCmd.exe by default,
must be in the working directory or in sys.path, or the path can be provided using the usbswitchcmd_exe_path parameter.
:param usbswitchcmd_exe_path: Path to the usbswitchcmd executable.
:param serial_number: Serial number of the correct switch as string. Not required if only one switch is connected.
"""
_CLASS_TYPE = "implementation"
[docs]
def __init__(self, device_number: int, dll_path: str|None=None):
super().__init__()
ClewareHumidity.set_dll_path(dll_path)
# self.serial_number = serial_number
self.device_number = device_number
log.info(f"Opening dll: '{ClewareHumidity.DLL}'")
self.dll = windll.LoadLibrary(ClewareHumidity.DLL)
self.cw = self.dll.FCWInitObject()
n_devs = self.dll.FCWOpenCleware(0)
ret = self.dll.FCWStartDevice(0, self.device_number)
if ret == 0:
log.error(f"Error starting sensor, StartDevice returned 0")
self.serial_number = self.dll.FCWGetSerialNumber(0, self.device_number)
[docs]
def is_on(self) -> bool:
return True # TODO
cmd = "-r"
ret, out, err = self.run_cmd(cmd)
if out == "1":
return True
elif out == "0":
return False
else:
raise RuntimeError(f"Failed to read USB switch status.\nCommand: '{cmd}'\nCode: {ret}, stdout: '{out}', stderr: '{err}'")
[docs]
def get_humidity_percent(self) -> float:
# use Integer version which returns value * 1000
return self.dll.FCWIGetHumidity(0, self.device_number) * 1e-3
[docs]
def get_temperature_C(self) -> float:
# use Integer version which returns value * 1000
return self.dll.FCWIGetTemperature(0, self.device_number) * 1e-3
[docs]
def is_connected(self) -> bool:
try:
self.get_temperature_C()
return True
except Exception as e:
log.error(e)
return False
[docs]
@staticmethod
def set_dll_path(dll_path=None) -> list[str]:
"""
After running this function the static variable DLL will be initialized to the dll path.
:param dll_path:
:return:
"""
if dll_path is None:
log.debug(f"No path to USBaccessX64.dll path specified, searching in path and working directory.")
if ClewareHumidity.DLL is None:
ClewareHumidity.DLL = search_in_path(ClewareHumidity.DEFAULT_DLL_NAME)
else:
ClewareHumidity.DLL = dll_path
USB_TYPES = {
0: "ILLEGAL_DEVICE",
1: "LED_DEVICE",
2: "POWER_DEVICE",
3: "DISPLAY_DEVICE",
5: "WATCHDOG_DEVICE",
6: "AUTORESET_DEVICE",
7: "WATCHDOGXP_DEVICE",
8: "SWITCH1_DEVICE",
9: "SWITCH2_DEVICE",
10: "SWITCH3_DEVICE",
11: "SWITCH4_DEVICE",
12: "SWITCH5_DEVICE",
13: "SWITCH6_DEVICE",
14: "SWITCH7_DEVICE",
15: "SWITCH8_DEVICE",
16: "TEMPERATURE_DEVICE",
17: "TEMPERATURE2_DEVICE",
21: "TEMPERATURE5_DEVICE",
32: "HUMIDITY1_DEVICE",
33: "HUMIDITY2_DEVICE",
40: "SWITCHX_DEVICE",
48: "CONTACT00_DEVICE",
49: "CONTACT01_DEVICE",
80: "ADC0800_DEVICE",
81: "ADC0801_DEVICE"
}
[docs]
@staticmethod
def _enumerate_devices(dll_path=None) -> list[str]:
devs = []
ClewareHumidity.set_dll_path(dll_path)
dll = windll.LoadLibrary(ClewareHumidity.DLL)
cw = dll.FCWInitObject()
n_devices = dll.FCWOpenCleware(0)
for i in range(n_devices):
devType = dll.FCWGetUSBType(0, i)
if devType in [16, 17, 21, 32, 33]:
sernum = dll.FCWGetSerialNumber(0, i)
devs.append(ClewareHumidity.USB_TYPES[devType] + f" (n={i}, sernum={sernum})")
dll.FCWCloseCleware(0)
return devs
[docs]
@staticmethod
def connect_device(device_name: str, dll_path: str|None=None):
"""
:param name: String with either "Device X" or "SerNum=X". If both are present SerNum=X takes precedence.
:return: Device instance
"""
m = re.search(r"n=(\d+)", device_name)
if m:
return ClewareHumidity(device_number=int(m.group(1)), dll_path=dll_path)
raise ValueError(f"Invalid Cleware switch name: {device_name}")
DLL = None
DEFAULT_DLL_NAME = "USBaccessX64.dll"
[docs]
def __repr__(self):
return f"Cleware Humidity" + (f" SerNum={self.serial_number}" if self.serial_number else "") + f" Nr={self.device_number}"