GL.iNet GL-MT3600BE: Using the Hardware Toggle Button to Control Fan Speed

fan.sh

I’m trying to use the MT-3600BE’s toggle switch to control fan speed.

In the GL.iNet web UI, the toggle switch can be assigned to different functions (LED, Wi-Fi, Repeater, Fan, etc.). When the switch is flipped, GL.iNet executes the corresponding script under:

/etc/gl-switch.d/

What works

These scripts behave exactly as expected for led.sh

Flipping the switch triggers the action immediately, and I can see related logs in logread -f

The issue

I added my own script:

/etc/gl-switch.d/fan.sh

It shows up in the UI and can be selected as the switch function, but flipping the switch does nothing:

  • No fan speed change
  • No log output
  • logread -f shows nothing related to fan

So the script is visible to the UI, but it never gets executed by the switch handler.

Temporary workaround

As a test, I modified led.sh (keeping a backup as led.sh.back) and reused it to control the fan:

#!/bin/sh

state="$1"
logger -t gl-switch-fan "gl-switch: state=$state"

if [ "$state" = "on" ]; then
    # Force fan to full speed
    /etc/init.d/gl_fan stop
    echo 255 > /sys/class/hwmon/hwmon0/pwm1 2>/dev/null
else
    # Back to automatic control
    /etc/init.d/gl_fan restart
fi

This works perfectly when bound to the switch, which confirms:

  • Fan control itself works
  • The toggle switch mechanism works
  • The problem is specifically that fan.sh is not being dispatched

Why I’m doing this

I’m running Docker from a USB disk on this router, and the USB drive temperature gets quite high. Forcing the fan to full speed helps a lot, but hijacking led.sh is obviously not ideal.

I’ll keep investigating how to properly use fan.sh

When I click the Apply button with “fan” selected, the web UI sends a POST request to http://192.168.8.1/rpc with the following payload:

{
    "jsonrpc": "2.0",
    "id": 31,
    "method": "call",
    "params": [
        "xxxxxxxxxxxxxxxxx",
        "switch-button",
        "check_sync_status",
        {
            "func": "fan"
        }
    ]
}

The response is rejected with:

{
    "id": 31,
    "jsonrpc": "2.0",
    "result": {
        "err_msg": "invalid parameter",
        "err_code": -1
    }
}

I think there may be some kind of whitelist configuration, or it might be hard-coded in the binary.