The AME Stack
The AME Stack=
I found that I wanted to deploy multiple devices of the same kind, but without having to change the configuration in multiple files. And I would like to simply plug in capabilities like measuring temperature or switching a relay. From an architectural standpoint, I prefer MQTT to interface with TCP, not with the ESP8266. As buffers are limited and awkward to handle (make them too big and memory is gone; make them too small and you'll get overruns), streaming is the preferred mode of data exchange. I want my code to be readable by humans. And, yes, this can be done. Even in the limited Arduino environment.
And thus generation 3 of my MQTT stack was born (and it is still growing up).
AC_ESP8266
AC_ESP8266 provides access to the ESP8266 on C++ level, no more, no less. It uses two (blowing my own horn) pretty clever functions to compose commands and to parse responses based on pattern expansion/ matching. The buffer used for commands and responses is the only one in the whole class, as writing and reading IP data is performed streaming. Callbacks announce the arrival of data and loss of connection.
AC_TCP_ESP8266
AC_TCP_ESP8266 provides streaming TCP functionality based on - you guessed it - the ESP8266. It deals with loss of TCP and WLAN connectivity and does what is required to get the ESP working again, which,frankly sometimes is not easy and a pain in the back. This includes resetting the chip via software and - optionally - hardware (it uses the reset pin of the ESP). If you want to, it even can turn the ESP off and on again. I think that does exhaust all options available.
AC_MTTQ
AC_MTTQ provides standard MQTT functions with QoS 0 or 1 (or more honestly "0.5" as ACKs message from the broker properly, but arriving ACKs are discarded and missing ACKs dont' prompt retries). Unlike other libaries AC_MQTT does not get unhappy if a ping response gets lost while performing publish and subscribe operations.
AC_IoT
AC_IoT provides convenience on device level with concepts such as centrally setting a device name and an MQTT-ID that get used wherever appropriate. In example, a device with MQTT-ID "garden01" uses "garden" as a prefix for topics in publications and subscriptions.
Devices
Devices report the version of the IoT framework, their own version, IP and MAC address, and number of connect attempts when the MQTT connection is established. In example, the messages
- "garden/versionIoT 1.038"
- "garden/version 1.010"
- "garden/connectAttempts 12"
- "garden/ip 192.168.2.76"
- "garden/mac 5d:de:ad:be:ef"
would be sent.
Capabilities
Capabilities can easily be added to a device. For a gardening system you maybe add capabilities "temperature", "spoil moisture", "rain", and "relay" (ie, to turn an irrigation system on and off). A capability encapsulates hardware intricacies, posses a built-in name, and provides configuration options such as a capability ID (a number), update intervals, I/O pins and so on.
In example, a capability encapsulating a BMP280 air pressure and temperature sensor with the built-in name "pressure" has been assigned capability ID "1". The capability will produces publications at a configurable interval using the name of the device, the name of the capability, the capability ID, and the attribute name. Building on the example above, publications would use the topic "garden/pressure01/pressure" and "garden/pressure01/temperature".
Additionally, Capabilities report their version and input and output parameters when the MQTT connection is established. In example, the messages
- "garden/pressure01/version 1.001"
- "garden/pressure01/capa01 <pressure:<d>" and
- "garden/pressure01/capa02 <temperature:<d>"
would be sent, indicating the production of two output attributes with the names "pressure" and "temperature" with numeric output format.