Fan regulator control from Arduino
To control AC power for inductive load (motor) a Triac is used. The concept is called phase cutting. It works for a resistive load (heater) too.

This module is designed for phase cutting. It contains a zero crossing detector and a Triac. The control is done in MCU. The zero crossing detector is wired to an interrupt pin. The control signal for the Triac is wired to an output pin. In external interrupt function you set a timer interrupt to send a pulse to the Triac after some microseconds. Longer off time results in less power for the motor.



At 50 Hz AC, one pulse is 10 milliseconds. To cut a part of AC wave out, activate the Triac gate for 20 microseconds after 0 to 10 milliseconds. Triac turns self off the AC line at next zero crossing.

Robotdyn has a library for the module.

EDIT: 

I bought the Robotdyn AC dimmer module to use it in my AC heater regulation project and I tested it with a incandescent light bulb and a fan. (video on youtube)

The library by Robotdyn works, but it is designed to control many dimmers and uses a timer interrupt every 12 microseconds (yes, micros). The library sets the interrupts over MCU registers. 

I wrote an adrduino fade-in/out sketch using TimerOne library to demonstrate phase cutting with this module.

#include &lt;TimerOne.h&gt;

const byte INTERRUPT_PIN = 2;
const byte TRIAC_PIN = 4;
const byte TRIAC_PULSE_MICROS = 30;

const int FADE_MAX = 9800;
const int FADE_MIN = 2000;

volatile bool triacOn;
volatile int period = FADE_MIN; // microseconds cut out from AC pulse

int fadeAmount = 10;

void zeroCrossing() {
  triacOn = false; // triac tuns off self at zero crossing
  Timer1.setPeriod(period); // to call triacPulse() after off period
}

void triacPulse() {
  if (triacOn) { // stop pulse
    digitalWrite(TRIAC_PIN, LOW);
    Timer1.stop();
  } else { // start pulse
    digitalWrite(TRIAC_PIN, HIGH);
    triacOn = true;
    Timer1.setPeriod(TRIAC_PULSE_MICROS);
  }
}

void setup() {
  pinMode(TRIAC_PIN, OUTPUT);
  attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), zeroCrossing, RISING);
  Timer1.initialize();
  Timer1.attachInterrupt(triacPulse);
}

void loop() {
  period = period + fadeAmount;
  if (period &lt;= FADE_MIN || period &gt;= FADE_MAX) {
    fadeAmount = -fadeAmount;
  }
  delay(25);
}


EDIT 2 version with triac activated by 'pwm' pin

const byte TRIAC_PIN = 9;
const byte ZC_EI_PIN = 2;

unsigned long topMicroseconds = 9700; // 10000 micros is between zero crossings
int prescaler = 8;
byte prescalerBits = _BV(CS11); // /8

void zeroCrossing() {
  TCNT1 = 0; // reset the timer counter
}

void setup() {
  Serial.begin(115200);
  Serial.println("START");

  attachInterrupt(digitalPinToInterrupt(ZC_EI_PIN), zeroCrossing, RISING);

  pinMode(TRIAC_PIN, OUTPUT);
  uint32_t topPeriod = ((F_CPU / 1000000)* topMicroseconds) / prescaler ;
  ICR1 = topPeriod;
  OCR1A = topPeriod + 1;
  TCCR1A = _BV(WGM11) | _BV(COM1A0) | _BV(COM1A1);
  TCCR1B = _BV(WGM13) | _BV(WGM12) | prescalerBits;
}

void loop() {
  if (Serial.available()) {
    unsigned long microseconds = Serial.parseInt();
    Serial.find("\n");
    uint32_t period = ((F_CPU / 1000000)* microseconds) / prescaler ;
    OCR1A = period;
  }
}


on SAMD it is possible to setup this to start the timer on external interrupt over event, without an interrupt function. then the CPU of the MCU is not involved in phase cutting after the initial configuration of the peripherals

EDIT 3:

The TriacDimmer library version 1.1.0 for AVR Arduinos available in Library Manager works good with this dimmer. Fun fact: It uses timer1's input capture on pin 8 instead of external interrupt on pin 2 or 3.