Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 36 additions & 2 deletions fanctrlplus.page
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ cpu_enable="0"
cpu_sensor=""
cpu_min_temp=""
cpu_max_temp=""
array_override_enable="0"
array_override_pwm="255"
INI
);
}
Expand Down Expand Up @@ -454,6 +456,7 @@ $(function() {
{ selector: 'input[id^="pwm_percent_input_"]', unit: '%', min: 0, max: 100 },
{ selector: 'input[id^="max_percent_input_"]', unit: '%', min: 0, max: 100 },
{ selector: `#idle_percent_input_${index}`, unit: '%', min: 0, max: 100 },
{ selector: `#array_override_percent_input_${index}`, unit: '%', min: 0, max: 100 },
{ selector: 'input[id^="low_temp_input_"]', unit: '°C', min: 1, max: 100 },
{ selector: 'input[id^="high_temp_input_"]', unit: '°C', min: 1, max: 100 },
{ selector: 'input[id^="cpu_low_temp_input_"]', unit: '°C', min: 1, max: 95 },
Expand All @@ -466,6 +469,11 @@ $(function() {
window.handleCpuEnableChange(this, index);
});

$html.find('select[id^="array-override-enable-"]').each(function () {
const index = this.id.replace('array-override-enable-', '');
window.handleArrayOverrideChange(this, index);
});

bindFanSpeedEvents();
bindIdleEvents();
}, 100);
Expand Down Expand Up @@ -605,6 +613,7 @@ $(function() {
{ selector: 'input[id^="pwm_percent_input_"]', unit: '%', min: 0, max: 100 },
{ selector: 'input[id^="max_percent_input_"]', unit: '%', min: 0, max: 100 },
{ selector: 'input[id^="idle_percent_input_"]', unit: '%', min: 0, max: 100 },
{ selector: 'input[id^="array_override_percent_input_"]', unit: '%', min: 0, max: 100 },
{ selector: 'input[id^="low_temp_input_"]', unit: '°C', min: 1, max: 100 },
{ selector: 'input[id^="high_temp_input_"]', unit: '°C', min: 1, max: 100 },
{ selector: 'input[id^="cpu_low_temp_input_"]', unit: '°C', min: 1, max: 95 },
Expand Down Expand Up @@ -871,7 +880,9 @@ $(function() {
cpu_enable: $block.find('select[name^="cpu_enable["]').val(),
cpu_sensor: $block.find('select[name^="cpu_sensor["]').val(),
cpu_min_temp: stripUnit($block.find('input[name^="cpu_min_temp["]').val()),
cpu_max_temp: stripUnit($block.find('input[name^="cpu_max_temp["]').val())
cpu_max_temp: stripUnit($block.find('input[name^="cpu_max_temp["]').val()),
array_override_enable: $block.find('select[name^="array_override_enable["]').val(),
array_override_percent: stripUnit($block.find('input[name^="array_override_percent["]').val())
};
$block.data('original', original);
}
Expand All @@ -896,7 +907,9 @@ $(function() {
cpu_enable: $block.find('select[name^="cpu_enable["]').val(),
cpu_sensor: $block.find('select[name^="cpu_sensor["]').val(),
cpu_min_temp: stripUnit($block.find('input[name^="cpu_min_temp["]').val()),
cpu_max_temp: stripUnit($block.find('input[name^="cpu_max_temp["]').val())
cpu_max_temp: stripUnit($block.find('input[name^="cpu_max_temp["]').val()),
array_override_enable: $block.find('select[name^="array_override_enable["]').val(),
array_override_percent: stripUnit($block.find('input[name^="array_override_percent["]').val())
};

if (JSON.stringify(original) !== JSON.stringify(current)) {
Expand Down Expand Up @@ -1414,6 +1427,18 @@ $(function() {
}
};

window.handleArrayOverrideChange = function(selectEl, index) {
const enabled = selectEl.value === "1";
const input = document.querySelector(`#array_override_percent_input_${index}`);
if (input) {
input.disabled = !enabled;
input.classList.toggle('disabled', !enabled);
}
document.querySelectorAll(`.array-override-control-${index} .array-override-label`).forEach(label => {
label.classList.toggle('disabled', !enabled);
});
};

// 初始化所有 block 的状态,并绑定 onchange
window.addEventListener('load', function () {
requestAnimationFrame(() => {
Expand All @@ -1425,6 +1450,15 @@ $(function() {
window.handleCpuEnableChange(this, index);
});
});

document.querySelectorAll('select[id^="array-override-enable-"]').forEach(select => {
const index = select.id.replace('array-override-enable-', '');
window.handleArrayOverrideChange(select, index);

select.addEventListener('change', function () {
window.handleArrayOverrideChange(this, index);
});
});
});
});
setTimeout(() => {
Expand Down
30 changes: 30 additions & 0 deletions include/FanBlockRender.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ function render_fan_block($cfg, $i, $pwms, $disks, $pwm_labels, $cpu_sensors) {
$idle_abs = isset($cfg['idle']) && is_numeric($cfg['idle']) ? (int)$cfg['idle'] : 0;
$idle_pct = round($idle_abs * 100 / 255) . '%';

$array_override_enable = ($cfg['array_override_enable'] ?? '0') == '1';
$array_override_pwm_raw = isset($cfg['array_override_pwm']) && is_numeric($cfg['array_override_pwm']) ? $cfg['array_override_pwm'] : 255;
$array_override_pct = round($array_override_pwm_raw * 100 / 255) . '%';

ob_start();
?>
<div class="fan-block" data-index="<?=$i?>" data-file="<?=htmlspecialchars($cfg['file'])?>">
Expand Down Expand Up @@ -193,6 +197,32 @@ class="interval-input fcp-interval-input"
</td>
</tr>

<!-- Mover / Parity Check Override -->
<tr>
<td class="fcp-help-cursor" title="When enabled, this fan runs at the fixed speed below whenever Unraid's Mover or a parity check/sync/rebuild is active, overriding the normal Disk/CPU calculation.">Override on Mover/Parity Check:</td>
<td>
<select id="array-override-enable-<?=$i?>" name="array_override_enable[<?=$i?>]" class="fcp-enable-select" onchange="handleArrayOverrideChange(this, <?=$i?>);">
<option value="0" <?=!$array_override_enable ? 'selected' : ''?>>Disabled</option>
<option value="1" <?=$array_override_enable ? 'selected' : ''?>>Enabled</option>
</select>
</td>
</tr>

<tr class="array-override-control array-override-control-<?=$i?>">
<td class="array-override-label fcp-help-cursor" title="Fixed fan speed to use while Mover or a parity check/sync/rebuild is running.">Override Speed:</td>
<td>
<input type="text"
id="array_override_percent_input_<?=$i?>"
name="array_override_percent[<?=$i?>]"
inputmode="numeric"
class="array-override-input fcp-input-fullleft"
value="<?=$array_override_pct?>"
title="Override speed: <?=$array_override_pct?> = <?=htmlspecialchars($array_override_pwm_raw)?> PWM"
placeholder="Speed %"
<?=!$array_override_enable ? 'disabled' : ''?>>
</td>
</tr>

<tr><td colspan="2" class="subhead">Disk Temperature Settings</td></tr>

<!-- Include Disk(s) -->
Expand Down
2 changes: 2 additions & 0 deletions include/FanctrlLogic.php
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,8 @@ function scan_dir($dir) {
cpu_sensor=""
cpu_min_temp=""
cpu_max_temp=""
array_override_enable="0"
array_override_pwm="255"
INI
);

Expand Down
9 changes: 9 additions & 0 deletions include/update.fanctrlplus.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,13 @@
$cpu_max_temp = '';
}

// Mover/Parity Check Override
$array_override_enable = $_POST['array_override_enable'][$i] ?? '0';
$array_override_percent_raw = $_POST['array_override_percent'][$i] ?? '';
$array_override_percent = is_numeric($ao = preg_replace('/[^0-9]/', '', $array_override_percent_raw)) ? intval($ao) : 100;
$array_override_percent = max(0, min(100, $array_override_percent));
$array_override_pwm = (int) round($array_override_percent * 255 / 100);

// Custom Name 不能为空
if ($custom === '') {
ob_clean();
Expand Down Expand Up @@ -195,6 +202,8 @@
'cpu_sensor' => $cpu_sensor,
'cpu_min_temp' => $cpu_min_temp,
'cpu_max_temp' => $cpu_max_temp,
'array_override_enable' => $array_override_enable,
'array_override_pwm' => $array_override_pwm,
];

$content = '';
Expand Down
26 changes: 26 additions & 0 deletions scripts/fanctrlplus_loop.sh
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,22 @@ plugin="fanctrlplus"
custom="${custom:-$(basename "$cfg_file" .cfg)}"
controller_enable="${controller}_enable"

# ===== Mover / Parity Check Override =====
array_override_enable="${array_override_enable:-0}"
array_override_pwm="${array_override_pwm:-$max}"

array_op_label() {
if pgrep -x mover >/dev/null 2>&1; then
echo "Mover"
return
fi
local resync
resync=$(/usr/local/sbin/mdcmd status 2>/dev/null | grep -Po '^mdResync=\K[0-9]+')
if [[ -n "$resync" && "$resync" -gt 0 ]]; then
echo "Parity"
fi
}

# 推导 RPM 读取路径
if [[ "$controller" =~ pwm([0-9]+)$ ]]; then
fan_index="${BASH_REMATCH[1]}"
Expand Down Expand Up @@ -138,6 +154,16 @@ while true; do
temp_origin="(Idle)"
fi

# Mover/Parity Check 覆盖:优先级最高,覆盖所有温控与 idle 结果
if [[ "$array_override_enable" == "1" ]]; then
array_op="$(array_op_label)"
if [[ -n "$array_op" ]]; then
pwm_val="$array_override_pwm"
max_temp="*"
temp_origin="($array_op)"
fi
fi

# 每轮都写入 Dashboard 缓存
echo "${max_temp} ${temp_origin}" > "/var/tmp/fanctrlplus/temp_${plugin}_${custom}"

Expand Down