diff --git a/frappy_psi/ionopimax.py b/frappy_psi/ionopimax.py index 221c848..75e64d1 100644 --- a/frappy_psi/ionopimax.py +++ b/frappy_psi/ionopimax.py @@ -18,60 +18,59 @@ # Jael Celia Lorenzana # ***************************************************************************** -import os -from glob import glob +"""support for iono pi max from Sfera Labs + +supports also the smaller model iono pi +""" + +from pathlib import Path from frappy.core import Readable, Writable, Parameter, BoolType, StringType,\ EnumType, FloatRange, Property, TupleOf, ERROR, IDLE -from frappy.errors import ConfigError, OutOfRangeError +from frappy.errors import ConfigError, OutOfRangeError, ProgrammingError from math import log -basepaths = '/sys/class/ionopimax', '/sys/class/ionopi' - class Base: addr = Property('address', StringType()) _devpath = None - devclass = None + _devclass = None + _status = None def initModule(self): super().initModule() - # candidates = glob(f'/sys/class/iono*/*/{self.addr}') - # if not candidates: - # raise ConfigError(f'can not find path for {self.addr}') - for basepath in basepaths: - for devclass in ([self.devclass] if isinstance(self.devclass, str) else self.devclass): - devpath = f'{basepath}/{devclass}' - if os.path.exists(f'{devpath}/{self.addr}'): - self._devpath = devpath - return - else: - self.log.info('%s does not exist', devpath) - else: - raise ConfigError(f'device path for {self.devclass} not found {devpath}') + candidates = list(Path('/sys/class').glob(f'ionopi*/*/{self.addr}')) + if not candidates: + raise ConfigError(f'can not find path for {self.addr}') + if len(candidates) > 1: + raise ProgrammingError(f"ambiguous paths {','.join(candidates)}") + self._devpath = candidates[0].parent + self._devclass = candidates[0].parent.name def read(self, addr, scale=None): - with open(f'{self._devpath}/{addr}') as f: + with open(self._devpath / addr) as f: result = f.read() if scale: return float(result) / scale - return result + return result.strip() def write(self, addr, value, scale=None): value = str(round(value * scale)) if scale else str(value) - with open(f'{self._devpath}/{addr}', 'w') as f: + with open(self._devpath / addr, 'w') as f: f.write(value) + def read_status(self): + if self.status is None: + return IDLE, '' + return self._status class DigitalInput(Base, Readable): value = Parameter('input state', BoolType()) - true_level = Property('level representig True', EnumType(low=0, high=1), default=1) - devclass = 'digital_in', 'digital_io' + true_level = Property('level representing True', EnumType(low=0, high=1), default=1) def initModule(self): super().initModule() - self.log.info('devpath %r', self._devpath) - if self.addr.startswith('dt'): - self.write(f'{self.addr}_mode','inp') + if self._devclass == 'digital_io' + self.write(f'{self.addr}_mode', 'inp') def read_value(self): return self.read(self.addr, 1) == self.true_level @@ -79,7 +78,24 @@ class DigitalInput(Base, Readable): class DigitalOutput(DigitalInput, Writable): target = Parameter('output state', BoolType(), readonly=False) - devclass = 'digital_out', 'relay' + + def read_value(self): + reply = self.read(self.addr) + try: + self._status = None + self.read_status() + value = int(reply) + except ValueError: + if reply == 'S': + if self.addr.startswith('oc'): + self._status = ERROR, 'short circuit' + else: + self._status = ERROR, 'fault while closed' + value = 0 + else: + self._status = ERROR, 'fault while open' + value = 1 + return value == self.true_level def write_target(self, value): self.write(self.addr, value == self.true_level, 1) @@ -87,9 +103,8 @@ class DigitalOutput(DigitalInput, Writable): class AnalogInput(Base, Readable): value = Parameter('analog value', FloatRange()) - rawrange = Property('raw range(electronic)', TupleOf(FloatRange(),FloatRange())) - valuerange = Property('value range(physical)', TupleOf(FloatRange(),FloatRange())) - devclass = 'analog_in' + rawrange = Property('raw range (electronic)', TupleOf(FloatRange(),FloatRange())) + valuerange = Property('value range (physical)', TupleOf(FloatRange(),FloatRange())) def read_value(self): x0, x1 = self.rawrange @@ -127,15 +142,14 @@ class CurrentInput(AnalogInput): def read_value(self): result = super().read_value() if self.x > 0.021: - self.status = ERROR, 'sensor broken' - raise OutOfRangeError('sensor broken') + self.status = ERROR, 'sensor fault' + raise OutOfRangeError('sensor fault') self.status = IDLE, '' return result class AnalogOutput(AnalogInput, Writable): target = Parameter('outputvalue', FloatRange()) - devclass = 'analog_out' def write_target(self, value): x0, x1 = self.rawrange @@ -156,7 +170,6 @@ class VoltageOutput(AnalogOutput): class VoltagePower(Base, Writable): - devclass = 'power_out' target = Parameter(datatype=FloatRange(0, 24.5, unit='V'), default=12) addr = 'vso'