from . import Backend as _Backend
from . import ManualMixin as _ManualMixin
from . import PIDMixin as _PIDMixin
+from . import TemperatureMixin as _TemperatureMixin
class Register (object):
return _struct.unpack('h', _struct.pack('H', melcor))[0] / decimal
def encode(self, value, **kwargs):
- if self.decimal:
- decimal = self.decimal
- elif self.decimal_offset:
+ decimal = self.decimal
+ if self.decimal_offset:
decimal *= self.decimal_offset
return self._float2melcor(value, decimal)
def decode(self, value, decimal=None):
- if self.decimal:
- decimal = self.decimal
- elif self.decimal_offset:
+ decimal = self.decimal
+ if self.decimal_offset:
decimal *= self.decimal_offset
return self._melcor2float(value, decimal)
return super(BoundedFloatRegister, self).decode(value, **kwargs)
-class MelcorBackend (_Backend, _ManualMixin, _PIDMixin):
+class MelcorBackend (_Backend, _ManualMixin, _PIDMixin, _TemperatureMixin):
"""Temperature control backend for a Melcor MTCA Temperature Controller
+
+ * PV: process temperature
+ * PV-units: degrees Celsius
+ * MV: controller current
+ * MV-units: amps
"""
+ pv_units = 'C'
+ mv_units = 'A'
+
# Relative register addresses from back page of Melcor Manual.
# Then I went through Chapter 6 tables looking for missing
# registers. References are from Series MTCA Thermoelectric
register = self._register[register_name]
if 'r' not in register.direction:
raise ValueError(register_name)
- if register.needs_decimal and not self._decimal:
- self._decimal = self._get_decimal()
+ if register.needs_decimal:
+ if not self._decimal:
+ self._decimal = self._get_decimal()
+ register.decimal = self._decimal
rc = self._client.read_holding_registers(
address=register.value, count=1, unit=self._controller)
assert rc.function_code < 0x80
register = self._register[register_name]
if 'w' not in register.direction:
raise ValueError(register_name)
- if register.needs_decimal and not self._decimal:
- self._decimal = self._get_decimal()
+ if register.needs_decimal:
+ if not self._decimal:
+ self._decimal = self._get_decimal()
+ register.decimal = self._decimal
v = register.encode(value, decimal=self._decimal)
_LOG.info('write %s: %s (%s)' % (register_name, v, value))
rc = self._client.write_register(
# Support for Backend methods
- def get_temp(self):
+ def get_pv(self):
return self._read('HIGH_RESOLUTION')
- def get_ambient_temp(self):
+ def get_ambient_pv(self):
return self._convert_F_to_C(self._read('AMBIENT_TEMPERATURE'))
- def set_max_current(self, max):
+ def set_max_mv(self, max):
"""Set the max current in Amps
0.2 A is the default max current since it seems ok to use
self._write('HIGH_POWER_LIMIT_BELOW', max_percent)
self._max_current = max
- def get_max_current(self):
+ def get_max_mv(self):
percent = self._read('HIGH_POWER_LIMIT_ABOVE')
above = percent/100. * self._spec_max_current
percent = self._read('HIGH_POWER_LIMIT_BELOW')
self._max_current = above
return above
- def get_current(self):
+ def get_mv(self):
pout = self._read('PERCENT_OUTPUT')
cur = self._spec_max_current * pout / 100.0
return cur
# ManualMixin methods
- def set_current(self, current):
+ def set_mv(self, current):
if current > self._spec_max_current:
raise ValueError('current {} exceeds spec maximum {}'.format(
current, self._spec_max_current))
proportional = max_current/propband
return (proportional, integral, derivative)
- def set_cooling_gains(self, proportional=None, integral=None,
- derivative=None):
+ def set_down_gains(self, proportional=None, integral=None,
+ derivative=None):
self._set_gains(
output=1, proportional=proportional, integral=integral,
derivative=derivative)
- def get_cooling_gains(self):
+ def get_down_gains(self):
return self._get_gains(output=1)
- def set_heating_gains(self, proportional=None, integral=None,
- derivative=None):
+ def set_up_gains(self, proportional=None, integral=None, derivative=None):
self._set_gains(
output=2, proportional=proportional, integral=integral,
derivative=derivative)
- def get_heating_gains(self):
+ def get_up_gains(self):
return self._get_gains(output=2)
def get_feedback_terms(self):