All communication via MQTT is handled by the brilliant library/framework called Homie. I am using version 2 which is extremely well documented. I let the ESP wake up, take it’s readings and then go to sleep for 2 minutes before the next reading.
I have simplified the main sketch by making a generic sensor class. All sensors are based on this class. It has the following features:
- A setup method that prepares the sensor. It has a state machine that keeps track of if the sensor is warmed up, if data is read and if they have been sent via MQTT.
- It has a readValue method that can be overloaded to provide data or the putValue method can be called if this sensor is not used inherited
- A handle method that should be called as often as possible from main loop. It updates the state machine
There is also a logging class that can be configured to display the wanted level of information through the serial interface. This is used extensivly around the entire sketch for easier debugging and documentation. Log level is set in Logging.h.
Each local sensor (connected directly to the ESP) has its own class for collecting data and sending it to the generic sensor class for reporting.
Each remote sensor (on the Pro Mini) has it’s own instance of the generic sensor class.
These libraries are neded for communicating with the local sensors:
- Adafruit BMP085 Library by Adafruit
- Adafruit CCS811 Library by Adafruit
- SparkFun TSL2561 by Mike Grusin@SparkFun Electronics
My entire code for the ESP8266 can be found on github here.
Arduino Pro Mini slave
The microcontroller handles some sensors and lets the ESP master pull them via I2C. Every two minutes the slave wakes up the ESP master for it to pull/send the readings.
The microcontroller works as an I2C slave. It stops sampling every two minutes and wakes up the master. It now listens for a one byte command from the master. Depending on the command it sends the respective data (eg. M=max volume, R=rms volume etc).
All values are floats. The master expects this
The microphone class is setting up the ADC in free running mode. This means that I am not using the standard Arduino AnalogRead() function! Big part of the code was borrowed from a great article by Arik Yavilevich
I changed the ADC prescaler divider so that it samples at 19,2 khz. This allows for measuring frequencies up to about 10khz.
The microphone is sampled in 100ms bursts. In this period nothing else is handled in the main loop. All these burst samples are accumulated and averaged when polled for data.
The PPD42 sensor is read by looking at the time it’s data pin is low. I have seen many busy-waiting examples on the internet, but decided to do my own interrupt driven version.
Originally I had the sensor on the ESP, but I was seeing many glitches. Maybe the onewire timings was disturbed by the wifi handling. I moved it to the slave, and now i get 99.9% good readings. I don’t like this sensor and it will later be replaced with the SI7021 that is I2C enabled.
These libraries are neded to talk to the sensors:
- DHT sensor library by Adafruit
My entire code for the Arduino Pro Mini can be found on github here.
I first started out with a design where master and slave was communication over I2C. I then decided to go for a solution where they communicated over SPI
I had a suspicion that the ESP SPI slave library I found was a bit unstable. It didn’t seem to run for more that 12 hours before my ESP restarted 🙁
I got another CO2 sensor for testing and put it on my AtMega in the beginning. It gave me a lot of headaches because it’s extremely noisy on the power supply. Whenever I added it to my circuit, my dust sensor readings went crazy.
After borrowing a scope i saw that it yanked my powersupply up/down 500 mV when it did a CO2 reading! Even with a 1000uF capacitor it still jumped 100mV which is too much for the PPD42 sensor.
I abandoned the sensor because the CCS811 seems better anyway. If you want my old code you can look here.
In part 4 I will tell little about the server side setup….