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.
This commit is contained in:
2025-11-27 17:55:52 +01:00
parent 3ede9eb9f4
commit 1bb869b43e
3 changed files with 166 additions and 19 deletions

94
cfg/gas10ka_cfg.py Normal file
View File

@@ -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',
)

View File

@@ -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 <markus.zolliker@psi.ch>
#
# *****************************************************************************
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()

View File

@@ -23,7 +23,7 @@ from ast import literal_eval
import snap7 import snap7
from frappy.core import Attached, Command, Readable, Parameter, FloatRange, HasIO, Property, \ from frappy.core import Attached, Command, Readable, Parameter, FloatRange, HasIO, Property, \
IDLE, BUSY, WARN, ERROR, Writable, Drivable, Communicator 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 frappy.errors import CommunicationFailedError, ConfigError
from threading import RLock from threading import RLock
@@ -77,24 +77,20 @@ class IO(Communicator):
self._plc = None self._plc = None
raise 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): class LogoMixin(HasIO):
ioclass = IO ioclass = IO
def get_vm_value(self, vm_address, scale=1): def get_vm_value(self, addr, scale=None):
return self.io.read(vm_address) * scale 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): def set_vm_value(self, addr, value, scale=None):
self.io.write(vm_address, round(value / scale)) if scale is None:
return self.io.read(vm_address) * scale 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): class DigitalActuator(LogoMixin, Writable):
@@ -231,9 +227,11 @@ class DelayedActuator(DigitalActuator, Drivable):
class Sensor(LogoMixin, Readable): class Sensor(LogoMixin, Readable):
addr = Property('VM address', datatype=StringType()) addr = Property('VM address', datatype=StringType())
scale = Property('scale to multiply with raw integer value',
NoneOr(FloatRange()), default=None)
def read_value(self): def read_value(self):
return self.get_vm_value(self.addr) return self.get_vm_value(self.addr, self.scale)
def read_status(self): def read_status(self):
return IDLE, '' return IDLE, ''
@@ -248,10 +246,10 @@ class AnalogOutput(Sensor, Writable):
self.output_addr = self.addr self.output_addr = self.addr
def read_value(self): 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): 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): class Pressure(Sensor):
@@ -263,9 +261,11 @@ class Resistor(Sensor):
class Comparator(LogoMixin, Readable): 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()) value = Parameter('airpressure state', datatype=BoolType())
threshold = Property('threshold for True', FloatRange()) threshold = Property('threshold for True', FloatRange())
def read_value(self): 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