ESP8266/ESP32 libraries released! LeifESPBase, LeifESPBaseHomie, LeifHomieLib

@rak, @Fa_Bien, @epicurean, @JGKK

Holy crap that was a lot of work. I spent all of today cleaning up, refactoring and testing my framework code, turning them into a proper libraries with example sketches and everything. I even made sure it compiles in the Arduino IDE, with both ESP8266 and ESP32!

I named the libraries after myself to avoid naming collisions and to not have to spend too much time thinking up names. Please feel free to rename your local copy :wink:

So, what do we have?

LeifHomieLib

Light weight homie v3 (MQTT) Library for ESP8266 and ESP32

No documentation yet but does have an example sketch!

It doesnā€™t have every homie feature but is well matched with openHAB.

Dependencies

AsyncMqttClient
ESPAsyncTCP

LeifESPBase

Base library for ESP8266/ESP32

Provides HTTP server, mDNS, simultaneous serial and telnet console output (for debugging), OTA update.

It is designed for use by programmers.

For example, SSID, Password, host name are hardcoded and not settable from any user interface.

These and other things were conscious design decisions that reduce code complexity and resource requirements.

Itā€™s designed to help in the construction of purpose-built specialty devices. It is not designed to build user-configurable devices.

As a programmer, I will always have a development environment set up and ready to upload new code to my devices through OTA.

This library depends on several great libraries listed below, which do most of the actual work. I am not claiming any ownership of those - LeifESPBase just ties them together.

Enter your WiFi SSID/key to environment_setup.h

Dependencies here:

dependencies (ESP32)

ArduinoOTA
ESP32
ESPmDNS
FS
Update
WebServer
WiFi

dependencies (ESP8266)

ArduinoOTA
ESP8266mDNS
ESP8266-ping
ESP8266WebServer
ESP8266WiFi
ESPAsyncTCP

And finally:

LeifESPBaseHomie

This ties both LeifESPBase and LeifHomieLib together to form the basis of a homie-capable ESP8266 or ESP32-based device!

Enter your WiFi SSID/key to LeifESPBase\environment_setup.h
Enter your MQTT credentials to LeifESPBaseHomie\environment_setup.h

All three can be found on my github account.

Iā€™m absolutely beat. But, tomorrow I will update my existing production projects (such as BedroomMCU) to use these libraries (rather than the pre-refactoring individual cpp files), and then release the ones people may be interested in. Itā€™s not worth putting those on github ā€“ they are tailor-made for their duties here, but I can release them as zip files for reference. Then Iā€™d better take a break from openHAB and get some ā€œreal workā€ done for a change. :slight_smile:

18 Likes

Big thank you. I will be able to look into this the next weekends. Well done.

1 Like

You the man! Thank you

1 Like

Yes thank you for doing the work and sharing it. Just have a quick question and that is does LeifHomieLib allow you to setup in AP mode so the wifi credentials donā€™t need to be hardcoded into the source and allows you to connect with a phone and setup the wifi details that way?

Is there a reason why you did not just use the esp32 V3 version of this project?

3 Likes

Thx for sharing!

1 Like

Well, I had already started on LeifESPBase (as separate source files) before I even started using openHAB and before learning about MQTT and Homieā€¦ but a couple of weeks ago when I knew I needed to make my devices homie compliant, I did actually look into the homie V3 version of that exact project. And thereā€™s a very good reason why I didnā€™t end up using it: It instantly crashed for me when I tried it. :slight_smile:

So why didnā€™t I debug it?

  • It was bigger than I wanted. The compiled size of the demo project was something like 550 KB, which would not fit on a 1MB ESP-01 if you want OTA.
  • The Homie V3 version of the library was in the middle of development, and it looked like it had been in development for a few months already. If it was a matter of a missing feature I might have been able to dive in and help, but the fact that it was instantly crashing means I never saw it do anything useful, and thatā€™s not a good entry point for a volunteer. Also, why would it take several months to release?? The spec looked simple enough, I figured I could make something in a weekend! Little did I know.

So, in the end I figured ā€œHow hard can it be!ā€ and started writing my own homie library. Famous last wordsā€¦

Anyway, itā€™s hopefully good for the community that thereā€™s another library publically available. This way, if someone else has my particular set of needs, thereā€™s something available to fill them. :slight_smile:

By the way, LeifHomieLib is not in any way dependent on LeifESPBase.

It doesnā€™t, because, what would that alone gain? There are so many other things that would need to be configuredā€¦ like the pin assignments for hardwareā€¦ or what the device should be doing at all. I could spend 10 or even 100 times the amount of time to make an infinitely configurable device, and end up with something that wonā€™t fit even on 4MB flashā€¦

ā€¦or, simply realize that there is already a user interface that lets you configure ALL of these things and moreā€¦ Drumrollā€¦ Itā€™s the Arduino IDE. Or, Sloeber once youā€™ve outgrown that.

I once read something interesting, might have been a geek comic or a programming blog. Something to the effect of:
ā€œAs frameworks grow excessively and become more and more extensive and bloated, inevitably they start resembling a bleak copy of the development environment used to create the framework.ā€
I tried finding it again now and couldnā€™tā€¦ but it is one of the truest adages about programming I have ever come across. Itā€™s just a matter of where you draw the line. When I develop a proprietary app, obviously that line is all the way up in the sky. The app has to be able to handle all target use cases by reconfiguration.

For a microcontroller, for me, the line is all the way down at the floor. Iā€™m a programmer. Iā€™m okay with recompiling it for every little thing, as long as I can OTA it to the target device.

1 Like

Great! Thank you for all these details!

1 Like

@leif
Thanks for the info, now I know if I want a stripped back version of Homie that still allows OTA updates to check yours out and what the main differences are as I have never used any form of Homie before. Keen to give it a try when the right project comes alongā€¦ There are many ways to approach a project and it is great to have another library with which to choose, so thanks heaps :+1::+1: My post was purely for this reason to help select which library to use.

I often program for other people who are not programmers so I have to make choices about which way suits the projects goals the most. Iā€™m sure you understand that, so there is no point saying more.

1 Like

Me too, usually! Not this time though. It is REFRESHING, I tell you! :joy:

By the way, it allows OTA updates but only through the development environment ā€“ NOT through Homie!

1 Like

FancyButton library released!

This is what handles all my 433 MHz remotes.
I spent most of the day writing a detailed example sketch.

@rak, @Fa_Bien, @epicurean, @JGKK

And, now that the underlying libraries are public, here is the full BedroomMCU project source code!

This is the source code for my air conditioning controller which I showed off here.

Please note that this is a Sloeber project. It will not build in the Arduino IDE.
It fact, I wouldnā€™t bother trying to build it ā€“ itā€™s not going to be useful beacuse itā€™s a completely custom project, designed for exactly the combination of hardware and appliances I have here. It can however be useful as a reference, to look at for ideas, and it is in that spirit alone that I am releasing it here. Iā€™m not putting it on github because it needs no further development ā€“ it is finished and in service.

I may modify it to use the TFT_eSPI library later but that wonā€™t affect actual functionality.

1 Like

Modified BedroomMCU to use TFT_eSPI. Screen updates are now INSTANT.

Also changed to an RLE format for the font so less memory is used as well. :slight_smile:

1 Like

Hi Leif & friends.
nice work and thank you for sharing your code
Iā€™m just a beginner and Iā€™ve the same problem ( old air conditioner with only one old IR remote control and I would love to switch on it with openhab.)
I wonder if you can give me some advice about the way you use to collect the command string to drive it by the ESPā€¦
Thanks
Ale
PS I mean the long strings you stored in the ir command matrix

ircommand ircommands[]=
{
IRDEF(air16),
IRDEF(air17),
IRDEF(air18),
IRDEF(air19),
IRDEF(air20),
IRDEF(air21),
IRDEF(air22),
IRDEF(air23),
IRDEF(air24),
IRDEF(air25),
IRDEF(air26),
IRDEF(air27),
IRDEF(air28),
IRDEF(air29),
IRDEF(air30),
IRDEF(air31),
IRDEF(air32),
IRDEF(airoff),
};

We had discussion about it on another thread. I used the IRdump code supplied as an example in the https://github.com/crankyoldgit/IRremoteESP8266 library. When used on an esp8266 with an ir receiver it prints the read codes to the serial console. This worked great for me but didnt work for @leif. He used one of the comercial solutions but I dont know which.
So I would recommend trying the dump example from the library and if that doesnt work maybe leif can recommend you his solution.
Johannes

Homie libraries: Please make a pull request on the Homie home page for linkage. homieiot.github.io

1 Like

Exactly as @JGKK said. I used AnalysIR. Itā€™s a dual-ended system, thereā€™s firmware that runs an Arduino Uno which you connect your IR receiver module to, and that in turn talks to their proprietary windows software. Itā€™s $30 and does exactly what it says it does. Not sure why the IRdump didnā€™t work for me. May as well try that first before you spend any money, but I will say that the AnalysIR software is quite nice and helps visualize and organize things.

Hereā€™s the user interface. I captured a few buttons from my Sharp TV remote that happened to be within reach.


After that, I went to the File menu, Batch Export, IRremote, and it placed the following on the clipboard:


/*
Automatically Generated by AnalysIR - Batch Export Utility
Registered to: leif@email-redacted
Session History
Type : Key : Value : Bits : Carrier Frequency (kHz)
0 : SHARP :  : 1050 : 13 : 37
1 : SHARP :  : 1090 : 13 : 38
2 : SHARP :  : 1010 : 13 : 35
3 : SHARP :  : 10E0 : 13 : 36
4 : SHARP :  : 1060 : 13 : 50
5 : SHARP :  : 10A0 : 13 : 36
6 : SHARP :  : 1020 : 13 : 41
7 : SHARP :  : 10C0 : 13 : 37
8 : SHARP :  : 1040 : 13 : 41
9 : SHARP :  : 1080 : 13 : 40
Note: Be sure to use the correct Carrier frequency, for each individual signal, as(or if) indicated above
*/

// NB: Not all protocols are supported by IRremote or IRLib. You may need to edit the code below manually
// Automatically Generated by AnalysIR for leif@email.redacted, visit https://www.AnalysIR.com/ or email info@....... for further details
int khz=38; //NB Change this default value as neccessary to the correct carrier frequency
irsend.sendSharp(0x1050, 13); //AnalysIR Batch Export (IRremote) // AnalysIR IR Protocol: SHARP, Key:  
irsend.sendSharp(0x1090, 13); //AnalysIR Batch Export (IRremote) // AnalysIR IR Protocol: SHARP, Key:  
irsend.sendSharp(0x1010, 13); //AnalysIR Batch Export (IRremote) // AnalysIR IR Protocol: SHARP, Key:  
irsend.sendSharp(0x10E0, 13); //AnalysIR Batch Export (IRremote) // AnalysIR IR Protocol: SHARP, Key:  
irsend.sendSharp(0x1060, 13); //AnalysIR Batch Export (IRremote) // AnalysIR IR Protocol: SHARP, Key:  
irsend.sendSharp(0x10A0, 13); //AnalysIR Batch Export (IRremote) // AnalysIR IR Protocol: SHARP, Key:  
irsend.sendSharp(0x1020, 13); //AnalysIR Batch Export (IRremote) // AnalysIR IR Protocol: SHARP, Key:  
irsend.sendSharp(0x10C0, 13); //AnalysIR Batch Export (IRremote) // AnalysIR IR Protocol: SHARP, Key:  
irsend.sendSharp(0x1040, 13); //AnalysIR Batch Export (IRremote) // AnalysIR IR Protocol: SHARP, Key:  
irsend.sendSharp(0x1080, 13); //AnalysIR Batch Export (IRremote) // AnalysIR IR Protocol: SHARP, Key:  


Unknown signals can be captured as RAW, and known protocols can be converted to RAW and exported.

Result:


/*
Automatically Generated by AnalysIR - Batch Export Utility
Registered to: leif@email.redacted
Session History
Type : Key : Value : Bits : Carrier Frequency (kHz)
0 : RAW :  :  :  : 37
1 : RAW :  :  :  : 38
2 : RAW :  :  :  : 35
3 : RAW :  :  :  : 36
4 : RAW :  :  :  : 50
5 : RAW :  :  :  : 36
6 : RAW :  :  :  : 41
7 : RAW :  :  :  : 37
8 : RAW :  :  :  : 41
9 : RAW :  :  :  : 40
Note: Be sure to use the correct Carrier frequency, for each individual signal, as(or if) indicated above
*/

// NB: Not all protocols are supported by IRremote or IRLib. You may need to edit the code below manually
// Automatically Generated by AnalysIR for leif@email.redacted, visit https://www.AnalysIR.com/ or email info@....... for further details
int khz=38; //NB Change this default value as neccessary to the correct carrier frequency


unsigned int Signal_0_0[] = {312,1804,288,756,288,760,288,756,288,760,288,756,288,1804,288,756,288,1800,288,760,288,756,288,756,288,760,288,1804,288,756,292,46948,264,1824,268,780,240,804,240,804,240,808,240,1876,244,776,240,1792,328,772,244,1700,416,1728,360,1848,244,1764,328,776,240,1852,264,42824,268,1752,340,776,240,804,240,804,244,804,240,804,244,1852,264,776,240,1880,240,776,240,804,244,804,240,804,244,1876,240,776,244}; //AnalysIR Batch Export (IRremote) - RAW

irsend.sendRaw(Signal_0_0, sizeof(Signal_0_0)/sizeof(int), khz); //AnalysIR Batch Export (IRremote) - RAW
 // AnalysIR IR Protocol: RAW, Key:  


unsigned int Signal_1_1[] = {248,1872,280,764,280,768,248,796,252,792,252,1840,276,768,256,788,248,1844,252,792,224,824,248,796,248,800,220,1868,252,792,248,46992,248,1872,252,792,220,824,224,820,224,824,224,824,220,1840,252,1864,224,824,248,1812,276,1840,252,1812,248,1872,276,768,248,1840,276,42788,320,1796,292,728,316,728,320,752,292,756,292,1796,292,716,332,752,292,1772,316,756,292,752,292,728,316,728,320,1772,316,728,316}; //AnalysIR Batch Export (IRremote) - RAW

irsend.sendRaw(Signal_1_1, sizeof(Signal_1_1)/sizeof(int), khz); //AnalysIR Batch Export (IRremote) - RAW
 // AnalysIR IR Protocol: RAW, Key:  


unsigned int Signal_2_2[] = {312,1804,288,760,284,760,284,760,288,760,288,756,288,760,284,760,284,1808,284,760,284,760,284,760,288,760,284,1808,284,760,284,48000,312,1804,284,760,288,756,288,760,284,764,284,1804,284,1804,288,1804,284,760,284,1804,284,1804,288,1804,284,1808,284,760,284,1804,288,41732,312,1808,280,764,284,760,284,764,284,760,288,760,284,760,284,760,284,1808,284,760,284,760,288,760,284,760,288,1804,284,760,284}; //AnalysIR Batch Export (IRremote) - RAW

irsend.sendRaw(Signal_2_2, sizeof(Signal_2_2)/sizeof(int), khz); //AnalysIR Batch Export (IRremote) - RAW
 // AnalysIR IR Protocol: RAW, Key:  


unsigned int Signal_3_3[] = {268,1848,272,776,272,772,272,772,244,804,240,1852,268,1820,268,1820,272,772,244,804,240,804,244,804,240,804,244,1848,240,804,240,45960,304,1808,284,764,252,792,280,764,284,764,288,756,292,756,288,756,288,1800,292,1800,288,1800,292,1796,292,1800,288,760,288,1800,288,43820,308,1808,284,760,284,764,284,760,284,764,284,1804,284,1804,284,1808,284,760,284,764,284,760,284,760,284,764,284,1808,280,764,284}; //AnalysIR Batch Export (IRremote) - RAW

irsend.sendRaw(Signal_3_3, sizeof(Signal_3_3)/sizeof(int), khz); //AnalysIR Batch Export (IRremote) - RAW
 // AnalysIR IR Protocol: RAW, Key:  


unsigned int Signal_4_4[] = {276,1812,300,748,268,776,272,776,268,776,272,776,268,1708,416,1736,348,748,268,776,272,772,272,776,272,772,272,1772,348,744,272,46996,268,1852,240,776,240,804,240,804,244,804,240,1880,240,776,240,804,240,1876,244,1632,456,1836,256,1668,420,1824,268,776,240,1748,368,42824,268,1848,244,772,244,804,240,804,240,808,240,804,240,1880,240,1848,240,776,244,804,240,804,240,804,244,804,240,1876,244,776,240}; //AnalysIR Batch Export (IRremote) - RAW

irsend.sendRaw(Signal_4_4, sizeof(Signal_4_4)/sizeof(int), khz); //AnalysIR Batch Export (IRremote) - RAW
 // AnalysIR IR Protocol: RAW, Key:  


unsigned int Signal_5_5[] = {312,1804,288,760,284,760,284,760,288,760,284,1808,284,760,284,1804,288,756,288,760,288,756,288,760,284,760,288,1804,284,760,288,46952,312,1804,284,764,284,760,284,760,284,764,284,760,288,1804,284,760,284,1804,284,1804,288,1804,284,1804,284,1808,284,760,288,1804,284,42780,312,1804,288,756,288,760,288,756,288,760,284,1804,288,756,288,1804,284,760,288,760,284,760,284,760,288,760,284,1804,288,760,284}; //AnalysIR Batch Export (IRremote) - RAW

irsend.sendRaw(Signal_5_5, sizeof(Signal_5_5)/sizeof(int), khz); //AnalysIR Batch Export (IRremote) - RAW
 // AnalysIR IR Protocol: RAW, Key:  


unsigned int Signal_6_6[] = {268,1824,268,776,240,804,244,804,240,804,244,804,240,804,244,1816,300,776,240,804,240,808,240,804,240,808,240,1820,272,800,244,48068,268,1780,312,776,240,804,240,804,244,804,240,1832,288,1748,316,800,240,1880,240,1776,312,1820,268,1788,304,1824,268,776,240,1848,268,41780,268,1768,320,780,240,804,240,804,240,808,240,804,240,808,240,1832,284,776,244,804,240,804,240,804,240,808,240,1880,240,776,240}; //AnalysIR Batch Export (IRremote) - RAW

irsend.sendRaw(Signal_6_6, sizeof(Signal_6_6)/sizeof(int), khz); //AnalysIR Batch Export (IRremote) - RAW
 // AnalysIR IR Protocol: RAW, Key:  


unsigned int Signal_7_7[] = {320,1800,288,728,320,724,320,728,316,732,316,1772,316,1776,316,728,316,728,320,724,320,724,320,756,292,728,316,1800,292,724,320,46948,320,1800,288,728,316,732,312,728,320,728,316,708,340,728,316,1772,320,1800,288,1800,292,1772,316,1772,316,1804,288,728,316,1800,292,42772,316,1800,292,728,276,768,276,768,304,744,276,1844,288,1800,288,728,276,768,280,768,304,740,308,736,304,744,308,1812,292,724,308}; //AnalysIR Batch Export (IRremote) - RAW

irsend.sendRaw(Signal_7_7, sizeof(Signal_7_7)/sizeof(int), khz); //AnalysIR Batch Export (IRremote) - RAW
 // AnalysIR IR Protocol: RAW, Key:  


unsigned int Signal_8_8[] = {268,1716,372,780,240,804,240,804,244,804,240,804,240,1776,344,776,240,804,244,804,240,804,240,804,244,804,240,1780,340,776,240,48072,268,1848,240,776,240,804,244,804,240,808,240,1820,296,776,240,1796,320,1824,268,1776,312,1824,268,1756,332,1852,240,776,244,1804,312,41780,264,1824,264,780,240,804,244,804,240,804,244,804,240,1876,240,776,244,804,240,804,240,804,244,804,240,804,244,1848,268,776,244}; //AnalysIR Batch Export (IRremote) - RAW

irsend.sendRaw(Signal_8_8, sizeof(Signal_8_8)/sizeof(int), khz); //AnalysIR Batch Export (IRremote) - RAW
 // AnalysIR IR Protocol: RAW, Key:  


unsigned int Signal_9_9[] = {268,1820,272,776,240,804,240,808,240,804,240,1760,360,776,240,804,240,808,240,804,240,804,240,808,240,804,240,1816,304,776,240,48072,240,1752,364,780,240,804,240,804,244,804,240,804,244,1752,360,1852,240,1636,456,1844,244,1820,268,1848,244,1728,364,772,244,1848,268,41780,264,1824,268,776,244,804,240,804,240,808,240,1848,244,800,244,804,240,804,240,804,244,804,240,804,244,804,240,1804,316,776,240}; //AnalysIR Batch Export (IRremote) - RAW

irsend.sendRaw(Signal_9_9, sizeof(Signal_9_9)/sizeof(int), khz); //AnalysIR Batch Export (IRremote) - RAW
 // AnalysIR IR Protocol: RAW, Key:  


Iā€™m not sure why it exports as unsigned int meaning 32 bits per value. I search-and-replaced with uint16_t because thatā€™s what the ā€œIRremoteESP8266ā€ library expects.

Done, PR created.

1 Like