+
 #include <Adafruit_PWMServoDriver.h>
 #include <Adafruit_NeoPixel.h>
 #include <Wire.h>
 #include <SoftwareSerial.h>
-
-/*
- * ToDo
- *  - Cycle through app [10 colours, count of how many to use, duration slider, blend amount 0-200%]
- *  - Vibrate On/Off/Set pattern
- *  - Tidy up code
- */
 
 enum LightMode {
   LightModeOff = 0,

        continue;

      // Parse and reset
      if (_bluetoothBuffer[0] == 'L')
        bluetoothLightCommand();
      else if (_bluetoothBuffer[0] == 'V')

  _lightStrip.show();
}

void vibrationPerformLoop() {  // Determine how long since we were last called - if we're within threshold then we do nothing
  uint64_t nowTime = millis();
  uint16_t timeSinceLast = (uint16_t)(nowTime - _vibrationLoopLastTime);
  if (timeSinceLast < 50) // Without this arbitrary delay the lower the delay is the more likely we get serial data corruption, the joys of hard-coded assembly
    return;
  _vibrationLoopLastTime = nowTime;

  // We need to determine where we are in the sequence by adding the ms offset and clamping it to total duration to cope with overflow
  _vibrationCycleCurrentOffsetTime += timeSinceLast;
  while (_vibrationCycleCurrentOffsetTime > _vibrationCycleDuration)
    _vibrationCycleCurrentOffsetTime -= _vibrationCycleDuration;
  
  // Now we enumerate through each motor's settings to determine where it currently is
  for (uint8_t pwmChannel = 0; pwmChannel < 9; pwmChannel++) {
    // Skip if there are no settings for this channel
    if (_vibrationSettings[pwmChannel].NumberValues < 1)
      continue;
    
    // Now based upon our current timestamp determine which value we should be using
    uint16_t startTime = 0;
    for (uint8_t valueIndex = 0; valueIndex < _vibrationSettings[pwmChannel].NumberValues; valueIndex++) {
      // If we have exceeded the end time for this value, simply update our start time and continue
      if (_vibrationCycleCurrentOffsetTime > _vibrationSettings[pwmChannel].Values[valueIndex].Duration + startTime) { 
        startTime += _vibrationSettings[pwmChannel].Values[valueIndex].Duration;
        continue;
      }
      
      // Determine how far through this segment we are
      float currentProgress = (float)(_vibrationCycleCurrentOffsetTime - startTime) / (float)_vibrationSettings[pwmChannel].Values[valueIndex].Duration;
      float diff = (int32_t)_vibrationSettings[pwmChannel].Values[valueIndex].End - (int32_t)_vibrationSettings[pwmChannel].Values[valueIndex].Start;
      uint16_t newValue = (uint16_t)(diff * currentProgress) + _vibrationSettings[pwmChannel].Values[valueIndex].Start;
      _pwmDriver.setPin(pwmChannel, newValue < 0 ? 0 : newValue > 4095 ? 4095 : newValue);
      
      // We've now set the value so we can break
      break;
    }
  }
}

void bluetoothParseInput() {
  // Return if no data to read
  uint32_t availableBytes = _bluetoothSerial.available();
