Sonoff SC with MQTT and Domoticz support
Last December Itead Studio updated their Home Automation product line with a new and different product. The main difference is that it doesn't have a relay and it's mainly sensors and no actuator (if we don't define a notifying LED as an actuator). The Sonoff SC is a sensor station that packs a DHT11 temperature and humidity sensor, a GM55 LDR, an electret microphone with an amplifier circuit and a Sharp GP2Y1010AU0F [Aliexpress] dust sensor in a fancy case that looks like it was originally meant for a speaker.
The device is packs an ESP8266 as expected and is compatible with the eWeLink app. But, such a collection of sensors, with 3 of them having analog interfaces, cannot be run from the single-ADC ESP8266 so Itead has thrown in a good old ATMega328P to drive the sensors and report the Espressif with the data.
The outside
The first thing that draw your attention about the Sonoff SC is it's casing. It's kind of a truncated hexagonal-ish pyramid with a round grid on top and a rounded bottom. Seriously, somebody had a good time designing this. It looks a lot like a intricate speaker and actually that's what it is. The reset/flash button sticks out shamelessly from a hole labelled “Audio” on one side of the enclosure.
Side by side with the fake audio hole there is an microUSB connector that's only for powering the device (no data lines connected) and a microSD slot. The microSD reader is connected to the ATMega328P and I'm not sure what original purpose it has but I can think on a couple of good things to do with it.
On the bottom you have 4 black screws. Remove them to gain access to the insides of the device.
The insides
Once the 4 screws are removed it can still be a little tricky to take the PCB out from the enclosure since the button shaft leaves little room to lift the PCB from the plastic holders. Meanwhile you try to remove it, take a look at the components on that bottom side of the PCB. There you can find the controllers and programming headers.
Upgrading the Sonoff SC
There are a couple of simple, almost out-of-the-box, upgrades you can do to your Sonoff SC. First you can easily replace the DHT11 termperature and humidity sensor with a more precise DHT22 (AM2302) [Aliexpress]. Both sensors are pin compatible. You can read great full comparison of them plus the Sensirion SHT71 [Aliexpress]. The DHT22 is better in accuracy and range to it's cheaper sibling, but it also has a short life expectancy, so after all it's a good idea to be able to replace it easily.
Off course replacing the sensor is not the full story, you will need to add support for the DHT22 to the firmware. More on this later on.
There is also an unused connector in the PCB meant for an LED. It's driven by GPIO D7 in the ATMega328P through a 2N7002 mosfet in reverse logic (set to LOW to turn on). Remember you have an LED on the PCB as well driven by GPIO13 of the ESP8266 also in reverse logic. The 5V pin is connected directly to the USB supply, so if you have a good power supply you may as well connect here an WS2812 LED ring [Aliexpress] for some colourful notifications. You will need a GND connection too but there are quite a few available (and properly labelled) on the board already.
New firmware for the Sonoff SC
This custom Sonoff SC firmware is released as **free open software **and can be checked out at my SonoffSC repository on Github.
So after making myself comfortable with the hardware of the device I started putting together some pieces grabbing code from other projects like the ESPurna firmware. The goal was to replace the code in the ATMega328 and the ESP8266 microcontrollers to be able to integrate the Sonoff SC into my home network. That means no cloud, that means MQTT.
While doing that I have added some features that came almost for free since I had already worked on them in other projects: Domoticz support for those that use that home automation platform and a “clap monitor". Yes. Clap your hands to switch on/off the lights.
Just like the original firmware, this custom firmware monitors temperature, humidity, noise level (in %), dust (in mg/m3) and light (in %).
Communication
First thing was to be able to send messages between the ATMega328P and the ESP8266. Itead Studio provides a simple firmware for the ATMega328P in the Sonoff SC wifi page. The firmware is a good starting point but I don't like it's architectured. Everything is too coupled.
So first thing was to create a communications library between both microcontrollers. I started looking for similar solutions and found out the SerialComm library by fjctp. It was almost what I was looking for but I liked the AT commands approach, one char keys are too minimal and naming is important. So I wrote the SerialLink library that allows me to:
- Compatible with AVR and ESP8266 ICs
- Define custom commands (the library is agnostic) like AT+TEMP
- Query command management (AT+TEMP=?)
- Optional automatic ACK responses
- Tolerant to noise in the line (debug output from the other controller)
- Callbacks for get and set values from the application
- Custom separator (=), terminator (\n) and query (?) chars
- Currently, it only accepts integer payloads
In the picture below you have a sample of the communication between both microcontrollers. The ESP8266 debug messages are quite verbose but only those starting with AT+… are answered by the ATMega328P. These are configuration messages “AT+EVERY=60” (set update interval to 60 seconds), “AT+CLAP=1” (enable clapping monitor) and “AT+PUSH=1” (enable message push from the ATMega328P to the ESP8266). Further down the log you start seeing MQTT messages due to push messages from the AVR about a clap code or sensor data.
The SerialLink library is currently bundled into my SonoffSC repository. I will create it's own repo soon.
MQTT and Domoticz
MQTT and Domoticz integration was easy since most of the code was already there in the ESPurna firmware. I configured the communication link for push messages so in the ESP8266 side I have a callback function that gets all the messages from the ATMega328P and dispatches them to the different outputs.
In this code fragment you can see how message keys are matched and messages are forwarded to three different clients: MQTT, Domoticz and broadcasted to websocket clients like the web interface.
bool commsSet(char * key, int value) {
char buffer[50];
if (strcmp_P(key, at_code) == 0) {
mqttSend(getSetting("mqttTopicClap", MQTT_CLAP_TOPIC).c_str(), value);
return true;
}
if (strcmp_P(key, at_temp) == 0) {
temperature = (float) value / 10;
mqttSend(getSetting("mqttTopicTemp", MQTT_TEMPERATURE_TOPIC).c_str(), temperature);
domoticzSend("dczIdxTemp", temperature);
sprintf(buffer, "{\"sensorTemp\": %s}", String(temperature).c_str());
wsSend(buffer);
return true;
}
...
}
Clap monitor
Now, this is more like a game feature. Don't know if it's really useful but it's certainly fun to play with. Have you ever wanted to move someone by clapping your room lights into romantic mode? Well, this feature is about that.
The algorithm for clapping recognition is somewhat hard if you want to make it reliable, remove false positives and avoid “losing” messages. It's not certainly suited for a noisy environments (I have kids at home…). My current approach is:
- The ATMega samples the mic analog output (amplified) in 20ms windows and calculates peak-to-peak values
- If peak-to-peak value is higher than a certain threshold during N consecutive time windows it flags it as a clap as remembers the current time in milliseconds
- From the second clap on it stores the time between claps (there is also some debouncing code here)
- After the last clap times out it checks if it has recorded any intervals (so that it has sensed a minimum of two claps in a row).
- Clap intervals are coded into binary values. The value always starts with a 1 and each interval pushes a new bit from the right ad shifts everything up. The first interval length is considered a “short” or a 0. If an interval is at least 1.5 times bigger than the first one it is read as a “long” or a 1.
- Finally the intervals array is reset and everything starts over again
This way I can encode clapping patterns as one byte codes. Two claps are always a “short” so it will be coded as b00000010 or 2. Three claps evenly spaced in time will be a b00000100 or 4. But if you leave a longer time (less than a second) between the second and third claps you get a b00000101 or 5.
I admit it's somewhat weird but you easily get used to it. “Clap, clap,… clap, clap” (that's a 10) and switch on the mirror light. “Clap, clap, clap, …. clap” (that's an 9) and there goes the living room one.
Right now clapping codes are sent by MQTT to a user defined topic. So it's a matter of having a service somewhere in you local network translating them to MQTT topics to perform different actions. This is a my test flow in Node-RED at home:
And the code of the “matching” function node is below. Those are ESPurna devices, payload 2 means toggle relay.
if (msg.payload == 9) {
msg.topic = '/home/living/lamp/relay/0';
msg.payload = 2;
} else if (msg.payload == 10) {
msg.topic = '/home/mirror/light/relay/0';
msg.payload = 2;
} else {
msg = null;
}
return msg;
And in the future…
There are some features I'd like to add in the future. One thing is that the device has a microSD slot connected to the SPI lines of the ATMega328P. Log sensor data to an SD card could be an option here for non-connected mode.
Also I'd like to be able to map clap codes to MQTT topics, hence not needing an external service like NodeRED to do that.
A neat feature would be to be able to OTA flashing the ATMega328P form the ESP8266. It should be possible with a minimum hardware hack: wiring the RST pin in the ATMega328P header to the SDA (GPIO2) pin in the ESP8266 header to reset the AVR programatically.
Also, there are some spare GPIOs available in the board that could be used to add more sensors (the SPI header exposes 3 digital pins, but shared with the SD). Ideas?
Flashing the ESP8266
Flashing the ESP8266 is very easy since the header close to it has all the required connections (3V3, TX, RX, GND) and the button is connected to GPIO0. Press and hold the button while powering the board to set the ESP8266 into flashing mode. You will have to remove the TX jumper in the board to avoid the ATMega328P to interfere in the upload process.
My recommendation is to flash an OTA enabled firmware as soon as possible as use OTA from then on to update the ESP8266 firmware. This way you can keep the jumpers in place and debug the communications to the AVR IC.
Flashing the ATMega328P
The ATMega328P comes flashed with the Arduino bootloader so all you have to do is connect a USB to UART programmer [Aliexpress] to it and flash it from the Arduino IDE or PlatformIO. Notice that labels in the header are from the programmer point of view (weird). So wire RX to your programmer RX, TX to your programmer TX and RST to DTR. Use 5V logic. Also, you don't want the ESP8266 interfere with the upload so remove the RX jumper that connects both microcontrollers. Actually remove both of them or the ESP8266 might complain with so much noise.
But, if you have an AVR programmer like the **USBASP v2 **[Aliexpress] below, it might be a better option to program the ATMega328P using the unpopulated ISP header in the board. This way you won't have to disconnect the jumpers between both controllers and have a stable test bed
Debugging
I'm using the ISP header to flash the ATMega328P and OTA to update the firmware in the ESP8266. This way I have everything connected and I can debug both microcontrollers using two USB to UART boards.
I use only RX lines connecting the RX of programmers to the RX pins in both headers (remember: RX to RX). Grounds are shared through my computer, but you might have to connect those too for better reliability.
Interface
The application web interface is stored in the ESP8266 using the same compression techniques I use for the ESPurna firmware. Right now you can:
- Check the current values from the sensors
- Configure up to 5 different WiFi networks (including the option for static IP)
- Configure the MQTT connection and topics for the different sensor data
- Configure the integration with Domoticz
- Change the hostname (used for the DNS discovery feature:
http://myhostname.local
) - Change the sensor update interval
- Enable/disable the clap monitor feature
The interface is based on jQuery and PureCSS. Here you have screenshots from the pages in the interface so you can get a better idea of what it can do at this moment.
Right now it's a fully working firmware replacement for the Sonoff SC. You will maybe miss some features from the original firmware. Let me know which ones. Use Github (link below) to report issues or feature requests.
This custom Sonoff SC firmware is released as **free open software **and can be checked out at my SonoffSC repository on Github.
Any comments are more than welcome.
"Sonoff SC with MQTT and Domoticz support" was first posted on 10 January 2017 by Xose Pérez on tinkerman.cat under Code, Hacking, Projects and tagged arduino, atmega328, avr, clap, dht11, dht22, domoticz, dust, electret, esp8266, espressif, espurna, ftdi, gp2y1010au0f, humidity, itead, jquery, ldr, light, microphone, mqtt, noise, purecss, seriallink, sht71, sonoff sc, temperature, usbasp, websockets.