ESP8266 Arduino SMTP Server part 2
Goal: Have a CK-PA9604 H.264 CCTV DVR send a signal on motion detected, to an arduino-programmed ESP8266 Wifi SMTP server, to sound a chime in a separate location.
Background: This specific 4-channel DVR can be set to detect motion in a defined area, and on detection either sound a (really annoying) 5-second beep, or send an email. Using an ESP8266 to detect the beep was considered and almost resorted to, but I’m a really determined programmer and in this instance was dedicated to learning how to execute a synchronous TCP handshake (SMTP) to achieve the goal.
The desired result is first and foremost, have the chime be more pleasant, and second, have the option of relaying the signal to a computer or smartphone or other device (and learn something new!)
Details of improvement: Since my last post, I hooked the DVR’s ethernet directly to a computer which bridged to the internet and was configured with Wireshark for packet monitoring. Through this tool I discovered that I’ve spent hours on a simple misunderstanding (isn’t it often the case?) – that the WifiClient class function flush() does not get called after a print(). I haven’t worked much with sockets since my VB6 days, and IIRC a flush command only forces a socket to send all data in the buffer.
The client.flush() command featured in my last post on this topic was called after every batch of data sent to the DVR. The actual flush() command clears the read buffer, so I was essentially clearing out the responses and encountering lots of failure. Oops.
The fixed up code:
Notes: This is a significant improvement over the last try. Note that all the challenge/responses are stored in an array, slimming up the code – yeah, the ESP has a huge flash memory, but this code is much less cluttered.
This code works with the DVR and doesn’t cause it to hang. To complete the intended effect, I tried using the tone() function of arduino libraries, but this doesn’t work. Instead, a beepC() function makes a less abrasive sound using pin toggles and delayMicroseconds() tuned to the frequency of this piezo.
For the ESP-01, the piezo (or an LED for that matter) can’t be tied between GPIO0 or GPIO2 – this triggers the bootloader. One user on esp8266.com forums came up with an ingenious idea of using a small electrolytic capacitor tied to plus volts to prevent the pins from hitting ground right away. This approach is great, except that if the module resets (say by watchdog timer), programming mode is entered. The ESP-01 seems to put out a frequency on both IO pins when in bootloader mode, and after about ten reflashes with the thing beeping the whole time, I knew there was another way lest I give up and try a simpler solution.
The final configuration has the piezo connected between GPIO0 and GPIO2. This connection doesn’t cause the module to enter flash, ever, even after a reset. On program initialization, one of the IO pins is set low and the other is switched to produce a tone.
Speaking of watchdog timers, I was getting “wdt reset” in my code occasionally. I turned off the wdt using ESP.wdtDisable() but soon found it was possible for the module to hang, in which case the wdt was quite useful. The WDT functions to reset the module if code stops executing, so we want to avoid too long of delay()s. The final solution to this was inserting yield() functions in a few choice locations.
At this point, the “test email” function seems to properly trigger the device, and I’ll have a chance soon to test it with an actual camera.
The only complaint with this is there’s a background noise being picked up by the piezo – a high pitched clicking or something like it. I haven’t figured out if its related to the ESP itself or the power supply, but in any case I’ll end up using either an RC filter or an external-driven piezo buzzer in the final product.