     return;
   Serial.read();  // Consume the copy msg;
   if (cmd.op == SET_PERIOD)  {
-    uint32_t new_period = kBrightnessToTime[cmd.value];
     switch (cmd.channel) {
-      case 0:
-        ssr1_setpoint_value = cmd.value;
-        ssr1_setpoint_us = new_period;
-        break;
-      case 1:
-        ssr2_setpoint_us = new_period;
-        ssr2_setpoint_value = cmd.value;
-        break;
-      case 2:
-        ssr3_setpoint_us = new_period;
-        ssr3_setpoint_value = cmd.value;
-        break;
-      case 3:
-        ssr4_setpoint_value = cmd.value;
-        ssr4_setpoint_us = new_period;
-        break;
-    }
-  } else if (cmd.op == SET_SMOOTHING) {
-    uint32_t new_smoothing = ((uint32_t) (cmd.value + 1)) << 2ul;
+      case 0: ch1.set_brightness(cmd.value); break;
+      case 1: ch2.set_brightness(cmd.value); break;
+      case 2: ch3.set_brightness(cmd.value); break;
+      case 3: ch4.set_brightness(cmd.value); break;
+    }
+  } else /* cmd.op == SET_SMOOTHING */ {
     switch (cmd.channel) {
-      case 0: ssr1_smoothing_us = new_smoothing; break;
-      case 1: ssr2_smoothing_us = new_smoothing; break;
-      case 2: ssr3_smoothing_us = new_smoothing; break;
-      case 3: ssr4_smoothing_us = new_smoothing; break;
+      case 0: ch1.set_duty_cycle_smoothing_rate(cmd.value); break;
+      case 1: ch2.set_duty_cycle_smoothing_rate(cmd.value); break;
+      case 2: ch3.set_duty_cycle_smoothing_rate(cmd.value); break;
+      case 3: ch4.set_duty_cycle_smoothing_rate(cmd.value); break;
     }
   }
   led2_state = led2_state ? LOW : HIGH;
   digitalWrite(LED2, led2_state);
 }
 
-void hm10_beacon_send_current_setpoints() {
+void hm10_beacon_send_current_brightness() {
   char buf[9];
-  sprintf(buf, "%02x%02x%02x%02x", ssr1_setpoint_value, ssr2_setpoint_value, ssr3_setpoint_value,ssr4_setpoint_value);
+  sprintf(buf,
+          "%02x%02x%02x%02x",
+          ch1.brightness(),
+          ch2.brightness(),
+          ch3.brightness(),
+          ch4.brightness());
   buf[9] = '\0';
   Serial.write(buf, sizeof(buf));
 }
 
-void StoreConfigToEEPROMIfChanged() {
-  if (!eeprom_is_ready())
-    return;
-  EEPROM.update(0, ssr1_setpoint_value);
-
-  if (!eeprom_is_ready())
-    return;
-  EEPROM.update(1, ssr2_setpoint_value);
-
-  if (!eeprom_is_ready())
-    return;
-  EEPROM.update(2, ssr3_setpoint_value);
-
-  if (!eeprom_is_ready())
-    return;
-  EEPROM.update(3, ssr4_setpoint_value);
-}
-
-void LoadConfigFromEEPROM() {
-  ssr1_setpoint_value = max(EEPROM.read(0), 31);
-  ssr2_setpoint_value = max(EEPROM.read(1), 31);
-  ssr3_setpoint_value = max(EEPROM.read(2), 31);
-  ssr4_setpoint_value = max(EEPROM.read(3), 31);
-
-  ssr1_period_us = kBrightnessToTime[ssr1_setpoint_value];
-  ssr2_period_us = kBrightnessToTime[ssr2_setpoint_value];
-  ssr3_period_us = kBrightnessToTime[ssr3_setpoint_value];
-  ssr4_period_us = kBrightnessToTime[ssr4_setpoint_value];
-
-  ssr1_setpoint_us = ssr1_period_us;
-  ssr2_setpoint_us = ssr2_period_us;
-  ssr3_setpoint_us = ssr3_period_us;
-  ssr4_setpoint_us = ssr4_period_us;
-}
-

#define SSR2_PIN A1
#define SSR3_PIN A2
#define SSR4_PIN A3

#define SSR_OFF LOW
#define SSR_ON HIGH

#define BEACON_NAME "living_room" /* 12 chars max */
#define BEACON_MAJOR "0xBEEF"
#define BEACON_MINOR "0x0001"
#define INITIAL_SMOOTHING_US 2000

enum op_type { SET_PERIOD = 0, SET_SMOOTHING = 1 };

union cmd_t {
  byte raw;
  struct {
    byte value : 5;
    byte channel : 2;
    enum op_type op : 1;
  };
};

const uint32_t kBrightnessToTime[] = {
  11000, 8365, 7986, 7661, 7369, 7100, 6848, 6608,
  6377, 6155, 5938, 5725, 5516, 5309, 5103, 4897,
  4691, 4484, 4275, 4062, 3845, 3623, 3392, 3152,
  2900, 2631, 2339, 2014, 1635, 1150, 700, 0
};

volatile uint32_t last_zerocross_isr_time;
uint32_t last_zerocross_time;

// Absolute time for the next SSR trigger.
uint32_t ssr1_trigger_time;
uint32_t ssr2_trigger_time;
uint32_t ssr3_trigger_time;
uint32_t ssr4_trigger_time;

// Setpoint [0-31] as recevaed by the beacon.
uint8_t ssr1_setpoint_value;
uint8_t ssr2_setpoint_value;
uint8_t ssr3_setpoint_value;
uint8_t ssr4_setpoint_value;

// Translated setpoint_value in us.
uint32_t ssr1_setpoint_us;
uint32_t ssr2_setpoint_us;
uint32_t ssr3_setpoint_us;
uint32_t ssr4_setpoint_us;

// Current period for smoothing. Convereges to setpoint_us.
uint32_t ssr1_period_us;
uint32_t ssr2_period_us;
uint32_t ssr3_period_us;
uint32_t ssr4_period_us;

// Smoothing factor.
uint32_t ssr1_smoothing_us;
uint32_t ssr2_smoothing_us;
uint32_t ssr3_smoothing_us;
uint32_t ssr4_smoothing_us;

uint16_t num_cycles;
uint8_t led2_state;


void setup()
{

#include <EEPROM.h>
#include <stdint.h>

#define BEACON_NAME "living_room" /* 12 chars max */
#define BEACON_MAJOR "0xBEEF"
#define BEACON_MINOR "0x0001"

#define LED1 12
#define LED2 11
