From 1bb869b43e3b2c9f4ceddb283dc6528c47c8059f Mon Sep 17 00:00:00 2001 From: l_samenv Date: Thu, 27 Nov 2025 17:55:52 +0100 Subject: [PATCH] capillary heater: heater is now a writable The value should show the actual heater power, but we do not know yet the address. Currently the value is just equal to the maxheater parameter. --- cfg/gas10ka_cfg.py | 94 ++++++++++++++++++++++++++++++++++ frappy_psi/capillary_heater.py | 53 +++++++++++++++++++ frappy_psi/logo.py | 38 +++++++------- 3 files changed, 166 insertions(+), 19 deletions(-) create mode 100644 cfg/gas10ka_cfg.py create mode 100644 frappy_psi/capillary_heater.py diff --git a/cfg/gas10ka_cfg.py b/cfg/gas10ka_cfg.py new file mode 100644 index 00000000..be23b628 --- /dev/null +++ b/cfg/gas10ka_cfg.py @@ -0,0 +1,94 @@ +Node('gas10ka.psi.ch', + '10kBar Gas pressure stick', + interface='tcp://5010', +) + +Mod('io', + 'frappy_psi.logo.IO', + '', + ip_address = "192.168.1.1", + tcap_client = 0x3000, + tsap_server = 0x2000 +) + +Mod('R_pt10k', + 'frappy_psi.logo.Resistor', + 'raw sensor value of T_p10k', + io = 'io', + addr = "VW0", +) + +Mod('T_pt10k', + 'frappy_psi.softcal.Sensor', + 'temperature close to sample', + value=Param(unit='K'), + rawsensor='R_pt10k', + calcurve='pt10000e', +) + +Mod('R_top', + 'frappy_psi.logo.Resistor', + 'raw sensor value of T_top', + io = 'io', + addr = "VW2", +) + +Mod('T_top', + 'frappy_psi.softcal.Sensor', + 'capillary temperature at highest position', + value=Param(unit='K'), + rawsensor='R_top', + calcurve='pt1000e', +) + +Mod('R_mid', + 'frappy_psi.logo.Resistor', + 'raw sensor value of T_mid', + io = 'io', + addr = "VW6", +) + +Mod('T_mid', + 'frappy_psi.softcal.Sensor', + 'capillary temperature at mid position', + value=Param(unit='K'), + rawsensor='R_mid', + calcurve='pt1000e', +) + +Mod('R_bot', + 'frappy_psi.logo.Resistor', + 'raw sensor value of T_bot', + io = 'io', + addr = "VW4", +) + +Mod('T_bot', + 'frappy_psi.softcal.Sensor', + 'capillary temperature at lower position', + value=Param(unit='K'), + rawsensor='R_bot', + calcurve='pt1000e', +) + + +Mod('R_sam_cx', + 'frappy_psi.logo.Resistor', + 'sensor', + io = 'io', + addr = "VW16", + ) + +Mod('T_sam_cx', + 'frappy_psi.softcal.Sensor', + '?', + value=Param(unit='K'), + rawsensor='R_sam_cx', + calcurve='X174785', +) + +Mod('heater', + 'frappy_psi.capillary_heater.Heater', + 'the capillary heater', + io = 'io', +) diff --git a/frappy_psi/capillary_heater.py b/frappy_psi/capillary_heater.py new file mode 100644 index 00000000..4ef4dfcb --- /dev/null +++ b/frappy_psi/capillary_heater.py @@ -0,0 +1,53 @@ +# ***************************************************************************** +# +# This program is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation; either version 2 of the License, or (at your option) any later +# version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along with +# this program; if not, write to the Free Software Foundation, Inc., +# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# Module authors: +# Markus Zolliker +# +# ***************************************************************************** + + +from frappy.core import Writable, BoolType, FloatRange, HasIO, Property, StringType, Parameter +from frappy_psi.logo import Sensor + + +class Heater(Sensor): + addr = 'VW10' # heater readback address + scale = 0.1 + switch_addr = Property('address for switch', StringType(), default='V0.1') + enable_addr = Property('address for enable', StringType(), default='V0.0') + maxheater_addr = Property('address for target', StringType(), default='VW10') + value = Parameter(unit='%') + switch = Parameter('heater is enabled', BoolType()) + enable = Parameter('heater enabled', BoolType(), readonly=False) + maxheater = Parameter('max. heater power', FloatRange(unit='%'), readonly=False) + + def read_switch(self): + return self.get_vm_value(self.switch_addr) + + def read_enable(self): + return self.get_vm_value(self.enable_addr) + + def write_enable(self, value): + self.set_vm_value(self.enable_addr, value) + return self.read_enable() + + def read_maxheater(self): + return self.get_vm_value(self.maxheater_addr, self.scale) + + def write_maxheater(self, value): + self.io.set_vm_value(self.maxheater_addr, value, self.scale) + return self.read_maxheater() diff --git a/frappy_psi/logo.py b/frappy_psi/logo.py index 6c2cf046..1c856e08 100644 --- a/frappy_psi/logo.py +++ b/frappy_psi/logo.py @@ -23,7 +23,7 @@ from ast import literal_eval import snap7 from frappy.core import Attached, Command, Readable, Parameter, FloatRange, HasIO, Property, \ IDLE, BUSY, WARN, ERROR, Writable, Drivable, Communicator -from frappy.datatypes import StringType, BoolType, IntRange, OrType, Int32 +from frappy.datatypes import StringType, BoolType, IntRange, NoneOr, Int32 from frappy.errors import CommunicationFailedError, ConfigError from threading import RLock @@ -77,24 +77,20 @@ class IO(Communicator): self._plc = None raise - @Command(StringType(), result=Int32) - def read(self, vm_address): - return self._plc.read(vm_address) - - @Command((StringType(), Int32)) - def write(self, vm_address, value): - self._plc.write(vm_address, value) - class LogoMixin(HasIO): ioclass = IO - def get_vm_value(self, vm_address, scale=1): - return self.io.read(vm_address) * scale + def get_vm_value(self, addr, scale=None): + if scale is None: + return int(self.io.communicate(addr)) + return float(self.io.communicate(addr)) * scale - def set_vm_value(self, vm_address, value, scale=1): - self.io.write(vm_address, round(value / scale)) - return self.io.read(vm_address) * scale + def set_vm_value(self, addr, value, scale=None): + if scale is None: + return int(self.io.communicate(f'{addr} {value}')) + reply = self.io.communicate(f'{addr} {round(value / scale)}') + return int(reply) * scale class DigitalActuator(LogoMixin, Writable): @@ -231,9 +227,11 @@ class DelayedActuator(DigitalActuator, Drivable): class Sensor(LogoMixin, Readable): addr = Property('VM address', datatype=StringType()) + scale = Property('scale to multiply with raw integer value', + NoneOr(FloatRange()), default=None) def read_value(self): - return self.get_vm_value(self.addr) + return self.get_vm_value(self.addr, self.scale) def read_status(self): return IDLE, '' @@ -248,10 +246,10 @@ class AnalogOutput(Sensor, Writable): self.output_addr = self.addr def read_value(self): - return self.get_vm_value(self.vm_address, self.scale) + return self.get_vm_value(self.addr, self.scale) def write_target(self, target): - return self.set_vm_value(self.vm_address, target, self.scale) + return self.set_vm_value(self.output_addr, target, self.scale) class Pressure(Sensor): @@ -263,9 +261,11 @@ class Resistor(Sensor): class Comparator(LogoMixin, Readable): - vm_address = Property('VM address', datatype=StringType()) + addr = Property('VM address', datatype=StringType()) + scale = Property('scale to multiply with raw integer value', + NoneOr(FloatRange()), default=None) value = Parameter('airpressure state', datatype=BoolType()) threshold = Property('threshold for True', FloatRange()) def read_value(self): - return self.get_vm_value(self.vm_address) > self.threshold + return self.get_vm_value(self.addr, self.scale) > self.threshold