Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
def _exec_page_plus_read(self, page, cmd, data_len, attempts=_READ_ATTEMPTS):
ret = None
for i in range(attempts):
self._wait()
self._write([0xad, 0, data_len + 2, 4, 0x60, CMD.PAGE_PLUS_READ, 2, page, cmd])
ret = self._read()
# in the captured traffic ret[2] == 0xff appears to signal a
# invalid data condition (probably related to the device being
# busy; see PMBus spec); TODO check PEC byte as well
if ret[0] == 0xaa and ret[1] == data_len + 2 and ret[2] == data_len:
break
assert ret, f'invalid response (attempts={attempts})'
return ret[3:(3 + data_len)]
def _exec(self, writebit, command, data=None):
self._write([_SLAVE_ADDRESS | WriteBit(writebit), CMD(command)] + (data or []))
return self._read()
def _set_all_fixed_speeds(self):
self._begin_transaction()
for channel in ['pump', 'fan']:
mtype, dmin, dmax = _LEGACY_FIXED_SPEED_CHANNELS[channel]
duty = clamp(self._data.load_int('{}_duty'.format(channel), default=dmax), dmin, dmax)
LOGGER.info('setting %s duty to %i%%', channel, duty)
self._write([mtype, duty])
return self._end_transaction_and_read()
def _prepare_profile(self, profile, min_duty, max_duty):
opt = list(profile)
size = len(opt)
if size < 1:
raise ValueError('At least one PWM point required')
elif size > _MAX_PROFILE_POINTS:
raise ValueError('Too many PWM points ({}), only 6 supported'.format(size))
for i, (temp, duty) in enumerate(opt):
opt[i] = (temp, clamp(duty, min_duty, max_duty))
missing = _MAX_PROFILE_POINTS - size
if missing:
# Some issues were observed when padding with (0°C, 0%), though
# they were hard to reproduce. So far it *seems* that in some
# instances the device will store the last "valid" profile index
# somewhere, and would need another call to initialize() to clear
# that up. Padding with (CRIT, 100%) appears to avoid all issues,
# at least within the reasonable range of operating temperatures.
LOGGER.info('filling missing %i PWM points with (60°C, 100%%)', missing)
opt = opt + [(_CRITICAL_TEMPERATURE, 100)]*missing
return opt
# keyword arguments may have been forwarded from cli args and need parsing
colors = list(colors)
self._begin_transaction()
if mode == 'fading':
if time_per_color is None:
time_per_color = 5
self._configure_device(fading=True, color1=colors[0], color2=colors[1],
interval1=clamp(time_per_color, 1, 255),
alert_temp=clamp(alert_threshold, 0, 100), color3=alert_color)
elif mode == 'blinking':
if time_per_color is None:
time_per_color = 1
if time_off is None:
time_off = time_per_color
self._configure_device(blinking=True, color1=colors[0],
interval1=clamp(time_off, 1, 255),
interval2=clamp(time_per_color, 1, 255),
alert_temp=clamp(alert_threshold, 0, 100), color3=alert_color)
elif mode == 'fixed':
self._configure_device(color1=colors[0], alert_temp=clamp(alert_threshold, 0, 100),
color3=alert_color)
elif mode == 'blackout': # stronger than just 'off', suppresses alerts and rainbow
self._configure_device(blackout=True, alert_temp=clamp(alert_threshold, 0, 100),
color3=alert_color)
else:
raise KeyError('Unsupported lighting mode {}'.format(mode))
self._end_transaction_and_read()
self._set_all_fixed_speeds()
def set_speed_profile(self, channel, profile, **kwargs):
"""Set channel to use a speed profile."""
if not self.supports_cooling_profiles:
raise NotImplementedError()
norm = normalize_profile(profile, _CRITICAL_TEMPERATURE)
# due to a firmware limitation the same set of temperatures must be
# used on both channels; we reduce the number of writes by trimming the
# interval and/or resolution to the most useful range
stdtemps = list(range(20, 50)) + list(range(50, 60, 2)) + [60]
interp = [(t, interpolate_profile(norm, t)) for t in stdtemps]
cbase, dmin, dmax = _SPEED_CHANNELS[channel]
for i, (temp, duty) in enumerate(interp):
duty = clamp(duty, dmin, dmax)
LOGGER.info('setting %s PWM duty to %i%% for liquid temperature >= %i°C',
channel, duty, temp)
self._write([0x2, 0x4d, cbase + i, temp, duty])
self.device.release()
def set_fixed_speed(self, channel, duty, **kwargs):
"""Set channel to a fixed speed duty."""
mtype, dmin, dmax = _LEGACY_FIXED_SPEED_CHANNELS[channel]
duty = clamp(duty, dmin, dmax)
self._data.store_int('{}_duty'.format(channel), duty)
self._set_all_fixed_speeds()
def set_instantaneous_speed(self, channel, duty, **kwargs):
"""Set channel to speed, but do not ensure persistence."""
if not self.supports_cooling:
raise NotImplementedError()
cbase, dmin, dmax = _SPEED_CHANNELS[channel]
duty = clamp(duty, dmin, dmax)
LOGGER.info('setting %s PWM duty to %i%%', channel, duty)
self._write([0x2, 0x4d, cbase & 0x70, 0, duty])
self.device.release()
def set_color(self, channel, mode, colors, time_per_color=1, time_off=None,
alert_threshold=_HIGH_TEMPERATURE, alert_color=[255, 0, 0],
speed=3, **kwargs):
"""Set the color mode for a specific channel."""
# keyword arguments may have been forwarded from cli args and need parsing
colors = list(colors)
self._begin_transaction()
if mode == 'rainbow':
if isinstance(speed, str):
speed = int(speed)
self._write([0x23, clamp(speed, 1, 6)])
# make sure to clear blinking or... chaos
self._configure_device(alert_temp=clamp(alert_threshold, 0, 100), color3=alert_color)
elif mode == 'fading':
self._configure_device(fading=True, color1=colors[0], color2=colors[1],
interval1=clamp(time_per_color, 1, 255),
alert_temp=clamp(alert_threshold, 0, 100), color3=alert_color)
self._write([0x23, 0])
elif mode == 'blinking':
if time_off is None:
time_off = time_per_color
self._configure_device(blinking=True, color1=colors[0],
interval1=clamp(time_off, 1, 255),
interval2=clamp(time_per_color, 1, 255),
alert_temp=clamp(alert_threshold, 0, 100), color3=alert_color)
self._write([0x23, 0])
elif mode == 'fixed':
def set_color(self, channel, mode, colors, time_per_color=1, time_off=None,
alert_threshold=_HIGH_TEMPERATURE, alert_color=[255, 0, 0],
speed=3, **kwargs):
"""Set the color mode for a specific channel."""
# keyword arguments may have been forwarded from cli args and need parsing
colors = list(colors)
self._begin_transaction()
if mode == 'rainbow':
if isinstance(speed, str):
speed = int(speed)
self._write([0x23, clamp(speed, 1, 6)])
# make sure to clear blinking or... chaos
self._configure_device(alert_temp=clamp(alert_threshold, 0, 100), color3=alert_color)
elif mode == 'fading':
self._configure_device(fading=True, color1=colors[0], color2=colors[1],
interval1=clamp(time_per_color, 1, 255),
alert_temp=clamp(alert_threshold, 0, 100), color3=alert_color)
self._write([0x23, 0])
elif mode == 'blinking':
if time_off is None:
time_off = time_per_color
self._configure_device(blinking=True, color1=colors[0],
interval1=clamp(time_off, 1, 255),
interval2=clamp(time_per_color, 1, 255),
alert_temp=clamp(alert_threshold, 0, 100), color3=alert_color)
self._write([0x23, 0])
elif mode == 'fixed':
self._configure_device(color1=colors[0], alert_temp=clamp(alert_threshold, 0, 100),
color3=alert_color)
self._write([0x23, 0])
elif mode == 'blackout': # stronger than just 'off', suppresses alerts and rainbow
self._configure_device(blackout=True, alert_temp=clamp(alert_threshold, 0, 100),