Controlling an Itead Sonoff B1 Color LED Bulb Using Blynk

The Itead Sonoff B1 color LED bulb is a 6W (2A maximum), 600lm output RGB full color, dimmable bulb with an integrated ESP8285 WIFI chip. As purchased it can be controlled via the EWeLink application. However, I wanted to incorporate the bulb into my existing home automation project which is primarily controlled via a Blynk application on my android phone.

In order to fully control the bulb, the Blynk application will require at least 5 slider widgets (one each for the RGB, cool and white colors). An additional button widget can be added to provide instant on/off capability and a timer widget could be used for scheduled operation. The timer widget option is not discussed here.

A quick search of the internet revealed directions on how to disassemble, connect to, and re-flash the ESP8285 chip. This process required soldering 4 wires to test points on the bulb’s PCB. The wires are then used to connect a USB-to-Serial type programmer. After reprogramming is completed, the wires are detached.

To disassemble the bulb, I used a small plastic wedge to assist in the removal of the translucent cover. My cover was lightly tacked in place through the use of 2 very small dabs of an extremely weak glue. I simply applied light pressure working my small plastic wedge around the perimeter of the cover, which then easily separated. The cover easily snapped back in place.

My replacement firmware code is below. Please note my choice of Blynk virtual pin numbers is purely arbitrary. Unlike other advice found on the Internet, I used the Arduino IDE’s Generic ESP8285 board, 1M (64 SPIFFS) flash size and DOUT upload settings during programming. Good luck.

/*************************************************************************
 * Title: Simple ESP-8266 Wifi Sonoff B1 LED Light Controller
 * File: sonoff_echo_blynk_sonoff_b1.ino
 * Author: James Eli
 * Date: 2/7/2019
 *
 * This program controls a Sonoff B1 RGB LED light via the blynk app. 
 * 
 * Notes:
 *  (1) To place an ESP8266 into program mode, GPIO0 must be LOW during power up. 
 *  (2) See: https://github.com/arendst/Sonoff-Tasmota/wiki/Sonoff-B1-and-B1-R2
 *  and: https://tinkerman.cat/sonoff-b1-lights-and-shades/
 *        
 * Upload Settings:
 *   Board: Generic Generic ESP8285
 *   Flash size: 1M (64 SPIFFS)
 *   Flash Mode: DOUT
*************************************************************************
 * Change Log:
 *   1/14/2018: Initial release. JME
 *************************************************************************/
#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>

// Blynk App authentication token, wifi ssid and password.
char auth[] = "2250996819bb490baee4dede77960053"; // Secondary Blynk app.
char ssid[] = "NETGEAR99";
char pass[] = "smoothtomato739";

// Sonoff B1/esp8266 pins.
#define DI_PIN  12 // GPIO12 
#define DCK_PIN 14 // GPIO14 
// Blynk virtual pins.
// V15 = red slider [0-255].
// V16 = green slider [0-255].
// V17 = blue slider [0-255].
// V19 = button [0-1]
// V20 = warm white slider [0-255].
// V21 = cool white slider [0-255].

// Slider values, initally set OFF.
int red = 0;
int green = 0;
int blue = 0;
int warmWhite = 0;
int coolWhite = 0;
// Button status.
int button = 0;

// Connect resync flag.
bool isFirstConnect = true;

// See MY9231 driver library @ https://github.com/xoseperez/my92xx
void pulseDI(uint8_t times)
{
  for (uint8_t i = 0; i < times; i++) 
  {
    digitalWrite(DI_PIN, HIGH);
    digitalWrite(DI_PIN, LOW);
  }
}

void pulseDCK(uint8_t times)
{
  for (uint8_t i = 0; i < times; i++) 
  {
    digitalWrite(DCK_PIN, HIGH);
    digitalWrite(DCK_PIN, LOW);
  }
}

void writeData(uint8_t data)
{
  // Send 8-bit data.
  for (uint8_t i = 0; i < 4; i++) 
  {
    digitalWrite(DCK_PIN, LOW);
    digitalWrite(DI_PIN, (data & 0x80));
    digitalWrite(DCK_PIN, HIGH);
    data = data << 1;
    digitalWrite(DI_PIN, (data & 0x80));
    digitalWrite(DCK_PIN, LOW);
    digitalWrite(DI_PIN, LOW);
    data = data << 1;
  }
}

void setupLED()
{
  // GPIO setup.
  pinMode(DI_PIN, OUTPUT);
  pinMode(DCK_PIN, OUTPUT);
  
  pulseDCK(64);                           // Clear all duty registers (2 chipes * 32).
  delayMicroseconds(12);                  // TStop > 12us.
  // Send 12 DI pulse, after 6 pulse's falling edge store duty data, and 12
  // pulse's rising edge convert to command mode.
  pulseDI(12);
  delayMicroseconds(12);                  // Delay >12us, begin send CMD data.
  // Send CMD data
  for (uint8_t n = 0; n < 2; n++)         // 2 chips in SONOFF B1.
    writeData(0x18);                      // ONE_SHOT_DISABLE, REACTION_FAST, BIT_WIDTH_8, FREQUENCY_DIVIDE_1, SCATTER_APDM
  delayMicroseconds(12);                  // TStart > 12us. Delay 12 us.
  // Send 16 DI pulse, at 14 pulse's falling edge store CMD data, and
  // at 16 pulse's falling edge convert to duty mode.
  pulseDI(16);
  delayMicroseconds(12);                  // TStop > 12us.
}

void setLED(uint8_t r, uint8_t g, uint8_t b, uint8_t w, uint8_t c)
{
  uint8_t duty[6] = { w, c, 0, g, r, b }; // RGBWC channels.

  delayMicroseconds(12);                  // TStop > 12us.
  for (uint8_t channel = 0; channel < 6; channel++) 
    writeData(duty[channel]);             // Send 8-bit Data.
  delayMicroseconds(12);                  // TStart > 12us. Ready for send DI pulse.
  pulseDI(8);                             // Send 8 DI pulse. After 8 pulse falling edge, store old data.
  delayMicroseconds(12);                  // TStop > 12us.
}

void setup() 
{
  // Init bulb LEDs.
  setupLED();
  // Set LEDs (initially off).
  setLED(red, green, blue, warmWhite, coolWhite);
  // Start Blynk.
  Blynk.begin(auth, ssid, pass);
}

void loop() { Blynk.run(); }

// Sync Blynk app and bulb. 
void syncPins()
{
  setLED(red, green, blue, warm, cool);

  if (button == 0 && (red || blue || green || warmWhite || coolWhite))
  { 
    Blynk.virtualWrite(V19, 1);
    button = 1;
  }
  
  if (button == 1 && !red && !blue && !green && !warmWhite && !coolWhite)
  {
    Blynk.virtualWrite(V19, 0);
    button = 0;
  }
}

// Read value from red, green, blue and brightness sliders.
BLYNK_WRITE(V15) { red = param.asInt(); syncPins(); }
BLYNK_WRITE(V16) { green = param.asInt(); syncPins(); }
BLYNK_WRITE(V17) { blue = param.asInt(); syncPins(); }
BLYNK_WRITE(V20) { warm = param.asInt(); syncPins(); }
BLYNK_WRITE(V21) { cool = param.asInt(); syncPins(); }

// Process Blynk ON/OFF button.
BLYNK_WRITE(V19)
{
  button = param.asInt();

  if (button == 1 && (red || blue || green || warmWhite || coolWhite))
    setLED(red, green, blue, warm, cool);
  else
  {
    setLED(0, 0, 0, 0, 0);
    Blynk.virtualWrite(V19, 0);
    button = 0;
  }
}

// Initial wifi connection sync.
BLYNK_CONNECTED()
{
  if (isFirstConnect)
  {
    Blynk.syncAll();
    isFirstConnect = false;
  }
}
Advertisements

About Jim Eli

µC experimenter
This entry was posted in iot and tagged , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s