I recently wrote about experimenting with the LILYGO TTGO ESP32 development board and my first attempts at using ESPHOME as against my firmware of choice Tasmota. Well, I’ve been heads-down for several days of learning – with several false starts I may add. The short version of this is, I’ve now made some significant progress in using ESPHOME on both ESP8266 and ESP32 (including finding the command to double the ESP8266 operating frequency from 80Mhz to 160Mhz – something often overlooked in the battle between the two chips). The point of writing this blog is to help save others some of my dead-ends and to serve as a reminder/prompt for me in the future.

Skip Background if you want the “shorter” (it’s not short) version – and head straight to The Meat but you may miss some useful context.

Background

Seasoned ESPHOME users may dismiss this, but this has been a challenge for me despite a history including decades of C programming and more recently delving into Javascript (NodeJS) thanks to Node-Red. Basically I started using machine code in the 1970s, moving on quickly through assembly language to BASIC, writing my own FORTH interpreter in a powerful BASIC version (Cromemco 23K Structured BASIC) sometime in 1980 or thereabouts. Around then I was convinced by an older friend that I was “barking up the wrong tree” and so came my introduction to C.

When I put together ESP-GO to program up ESP8266 chips for home control, I avoided C++ like the plague and stuck with plain old C (and the ESPRESSIF SDK) – not one of my better plans though I did manage to modify some Adafruit and other libraries to add LCD/OLED display, ws2812b RGB LEDs and various sensor controls to the ESP8266. Mix in some simple Node-Red NodeJS coding on Raspberry Pi (RPi2 initially) and I was starting to see results and a following on the blog. The route I took combined with the ESP8266 meant I was constantly up against RAM limits to that route was never going to last – it still works and I have a pair of ESP8266+ILI941 wall thermostats back in the UK which stand as a testament to ESP-GO – complete with local buttons and of course WiFi/MQTT control. All blogged in here.

And then came Tasmota which enjoys a lot of support to this day and by 2021 its display handling exceeds that of ESP-GO – yet for me still leaves something to be desired in that area. In the process of using the Raspberry Pi as my home control centre – along with Node-Red, I’ve been introduced to JSON though I would not say I was an expert on the subject or anything like it.

So, last week I went off on a tangent, grabbed both ESP8266 and ESP32 boards and went off to the web to see what ESPHOME is all about. The ESPHOME software system uses YAML (a “digestible data serialization language” that is often utilized to create configuration files, works in concurrence with any programming language and is apparently a superset of JSON – it is also utterly alien to me). ESPHOME is usually associated with “Home Assistant” and I am not a fan of the latter, which makes learning about ESPHOME that much more difficult as HA appears frequently throughout ESPHOME documentation. My thanks to @ssieb, @WeekendWarrier and others in the ESPHOME Discord forum for their help.

The Meat

So, to the meat – with unprecidented help from a couple of individuals in the ESPHOME forum, I started from zero last week and worked my way up to a usefully working ESP32 (TTGO) board including built-in IPS ST7789V 1.14 Inch LCD display, some ws2812b RGB lighting, a simple LED, a ~BME280 multi-purpose sensor and use of the on-board TTGO buttons (shown on the display using simple filled, colour-changing circles) – all using ESPHOME software. That reversed out text is black on yellow achieved with simple black text on top of a yellow filled rectangle.

TTGO board with ESPHOME - a work in progress

Above you see the hardware and below, the ESPHOME software in it’s current form. At the top of the panel, the internal chip temperature and WiFi connection state, then the output from the BME280 board (bottom left – I2C and 3v3), time, date any WiFi status. This will develop into something actually useful but I’m still learning – and it IS PRETTY. Shame the ws2812b LEDs don’t really show the constantly-cycling, individual-colour-per-LED rainbow effect in the photo. Trust me.

The code below (My First ESP32 ESPHOME Project) to go with the photo above, looks involved but I should point out here that it is built up largely from modified examples (I’ve left seemingly pointless comments in as reminders for my own future) pieced together and modified as I learn. My WiFi password is hidden to protect the innocent.

So, ESPHOME software appears to be built up in blocks (starting points for pretty much all of this can be seen spread around the ESPHOME website) – after installing the ESPHOME package on my PC – trivial – it’s all done for you and a plug-in called PILLOW for Python (again all automated setup), I started the ball rolling. ESPHOME works (in Windows) on the command line and using NotePad++ to edit the code the two of which that nearly put me off right at the start, until one of the people giving me advice said “No, what you need is this…. the new, free Windows Terminal – which pulls in Powershell and is EASY and pleasant to use, also the free Microsoft Visual Code for editing.”

With that starting point I made a start on ESPHOME.

Setup

I took a handy NODEMCU-type ESP8266 board and plugged it into a spare USB port on the PC using a standard USB lead.

At the prompt in Windows terminal – not paying any attention to folders though in fact I was sitting in the new”C:UsersUseresphome” folder, I simply started by typing:

esphome wizard myesp8266.yaml

— which is how you start off a brand new ESPHOME project. Bear in mind that NodeMCU-type boards do not need you to mess about with reset and programming (GPIO0) buttons – others may. In short – a new project we’ll call “fred” starts with an automatically-created fred.yaml file in the automatically created esphome folder… and ends up with a “fred” folder underneath – along with folders for whatever projects you create.

This is how it all starts in my case:

Hi there!
I’m the wizard of ESPHome 🙂
And I’m here to help you get started with ESPHome.
In 4 steps I’m going to guide you through creating a basic configuration file for your custom ESP8266/ESP32 firmware. Yay!

============= STEP 1 =============
_____ ____ _____ ______
/ ____/ __ | __ | ____|
| | | | | | |__) | |__
| | | | | | _ /| __|
| |___| |__| | | | |____
_________/|_| _______|

===================================
First up, please choose a name for your node.
It should be a unique name that can be used to identify the device later.
For example, I like calling the node in my living room livingroom.

(name):myesp8266

At this point I gave the project a name “myesp8266” – hardly imaginative but there you go. I was then asked if I was using an ESP32 or ESP8266 – I responded with the latter. I was then asked what TYPE of ESP8266 board – I responded with nodemcuv2 (a guess).

The advice at the end, above, is invaluable – as https://esphome.io is FULL of useful reference material and examples. At this point the PC came back to the prompt. No chip flashing had been done – so I left the board plugged into USB and the PC and took a look at the new YAML file in VSC (Visual Studio Code editor). Don’t ask me why it was called “myesphome” when I’d used “myesp8266” – but I just checked the file name – sure enough.

Out-of-the-box YAML code

Anyway, here (minus my password which I’ve left here as xxxxxxx) is the content of that file…

esphome:
name: myesp8266
platform: ESP8266
board: nodemcuv2

# Enable logging
logger:

# Enable Home Assistant API
api:
password: “”

ota:
password: “”

wifi:
ssid: “xxxxxxx”
password: “yyyyyyy”

# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: “Myesp8266 Fallback Hotspot”
password: “Olv9HILOgwrE”

captive_portal:

I’d already figured out at this point that I would not be needing the Home assistant API and would be needing MQTT but that will follow:

After that initial setup, a slightly changed command-line instruction (wizard replaced by run) created the first actual FLASHED ESP8266:

esphome run myesp8266.yaml

C:UsersUseresphome> esphome run myesphome.yaml
INFO Reading configuration myesphome.yaml…
INFO Generating C++ source…
INFO Compiling app…
INFO Running: platformio run -d myesp8266
Processing myesp8266 (board: nodemcuv2; framework: arduino; platform: platformio/[email protected])
———————————————————————————————————————————————————————————————–Verbose mode can be enabled via `-v, –verbose` option
CONFIGURATION: https://docs.platformio.org/page/boards/espressif8266/nodemcuv2.html
PLATFORM: Espressif 8266 (2.6.2) > NodeMCU 1.0 (ESP-12E Module)
HARDWARE: ESP8266 80MHz, 80KB RAM, 4MB Flash
PACKAGES:
– framework-arduinoespressif8266 3.20704.0 (2.7.4)
– tool-esptool 1.413.0 (4.13)
– tool-esptoolpy 1.20800.0 (2.8.0)
– toolchain-xtensa 2.40802.200502 (4.8.2)
LDF: Library Dependency Finder -> http://bit.ly/configure-pio-ldf
LDF Modes: Finder ~ chain, Compatibility ~ soft
Library Manager: Installing Update
Library Manager: Already installed, built-in library
Found 32 compatible libraries
Scanning dependencies…
Dependency Graph
|– <ESPAsyncTCP-esphome> 1.2.3
| |– <ESP8266WiFi> 1.0
|– <ESPAsyncWebServer-esphome> 1.3.0
| |– <ESPAsyncTCP-esphome> 1.2.3
| | |– <ESP8266WiFi> 1.0
| |– <Hash> 1.0
| |– <ESP8266WiFi> 1.0
| |– <ArduinoJson-esphomelib> 5.13.3
|– <ESP8266WiFi> 1.0
|– <ESP8266mDNS> 1.2
| |– <ESP8266WiFi> 1.0
|– <ArduinoJson-esphomelib> 5.13.3
|– <DNSServer> 1.1.1
| |– <ESP8266WiFi> 1.0
Building in release mode
Retrieving maximum program size .pioenvsmyesp8266firmware.elf
Checking size .pioenvsmyesp8266firmware.elf
Advanced Memory Usage is available via “PlatformIO Home > Project Inspect”
RAM: [==== ] 39.6% (used 32424 bytes from 81920 bytes)
Flash: [==== ] 37.8% (used 394400 bytes from 1044464 bytes)
================================================================================= [SUCCESS] Took 3.98 seconds =================================================================================INFO Successfully compiled program.
Found multiple options, please choose one:
[1] COM11 (USB-SERIAL CH340 (COM11))
[2] Over The Air (myesp8266.local)
(number): 1

You won’t like the totally automated output that follows (above) as it is very long and took a minute or two on my PC to run – but did you notice above – I only typed in “1” – and that is the last time for that project that the board needs to be plugged into the PC unless you want o see serial logging – from there on any old USB hub or USB supply will do (not connected to the PC) and there is no menu. I typed in “1” and a torrent of information poured out to tell me that the board was being “Flashed” and then to tell me that it was connected to the WiFi – for the sake of it, here’s some of that output.

[I][app:106]: ESPHome version 2021.8.2 compiled on Sep 26 2021, 12:15:48
[12:27:57][C][wifi:499]: WiFi:
[12:27:57][C][wifi:359]: SSID: ‘xxxxxxx’
[12:27:57][C][wifi:360]: IP Address: 192.168.1.238
[12:27:57][C][wifi:362]: BSSID: 94:83:C4:01:84:6E
[12:27:57][C][wifi:363]: Hostname: ‘myesp8266’
[12:27:57][C][wifi:367]: Signal strength: -59 dB ▂▄▆█
[12:27:57][C][wifi:371]: Channel: 1
[12:27:57][C][wifi:372]: Subnet: 255.255.255.0
[12:27:57][C][wifi:373]: Gateway: 192.168.1.1
[12:27:57][C][wifi:374]: DNS1: 192.168.1.1
[12:27:57][C][wifi:375]: DNS2: (IP unset)
[12:27:57][C][logger:189]: Logger:
[12:27:57][C][logger:190]: Level: DEBUG
[12:27:57][C][logger:191]: Log Baud Rate: 115200
[12:27:57][C][logger:192]: Hardware UART: UART0
[12:27:57][C][captive_portal:148]: Captive Portal:
[12:27:57][C][web_server:152]: Web Server:
[12:27:57][C][web_server:153]: Address: myesp8266.local:90
[12:27:57][C][ota:029]: Over-The-Air Updates:
[12:27:57][C][ota:030]: Address: myesp8266.local:8266
[12:27:57][C][api:095]: API Server:
[12:27:57][C][api:096]: Address: myesp8266.local:6053

Once done, I removed the USB lead from the PC and stuck the lead into a USB hub. The board powered up (not entirely true for my FIRST time as I got things wrong and forgot to add a WEB SERVER block so the board could be visibly seen to be working without serial – so let’s cheat a little). With the board now plugged into non-PC USB for power only – I added THIS (below) to the very end of YAML file… formatting is important so “web server:” needs to be on the left and that tab before “port: 80” is important as is the space before the 80 – port 80 is usually a good choice – I could have used another other port(90 for example) but 80 is the default choice for web pages and saves keying in a port number in the browser

I saved the file and used the RUN command as above.

At this point, here is a screenshot of myesp8266 in my browser (you might see :90 appended in the graphic – indeed ignore that top URL in the image below entirely – I got it wrong at first – your system may need myesp8266.local or myesp8266.broadband or similar. depends on the router or any customising that’s been done to it – in my case the line below is what I ended up keying into my browser…

http://myesp8266.lan

The router will have picked the IP address – you could FIX the IP address of course. The web page doesn’t actually DO anything at this point – but in my first projects the web server proved very useful, particularly for on-screen buttons while figuring out how to wire up and use REAL inputs.

AS time goes on I’ll flesh this out and show other test projects as they mature.

The rest – as you will see below is largely a case of adding blocks and modifying them to suit. Below is my first functioning TTGO project – there is no other code than what you see below. As well as SPI for the display, I also needed I2c – that is SO easy to add – just specify GPIO pins. That complex-looking BME sensor was just copied directly from an example on the ESPHOME site… What makes it DO something? It reports all by itself at regular intervals.

Once I learned that the term LAMBDA (see below code Lambda |- and the C (ish) code that follows it to drive the display and which refers to items in the YAML largely by ID… I simply used three lines of screen space to display temperature, humidity and pressure on the built-in display. If you read the code below you’ll see I refer to fonts and CSS colours – there is a fonts folder under ESPHOME and I simply downloaded a few standard TTF fonts into the fonts folder on my PC, the compiler using only what I needed – but this seems WAY more flexible than Tasmota font handling. Colours – I have a color folder with some simple definitions for useful colours… a file therein called COLOR_CSS_AQUAMARINE contains a little text only…

color:
# name and values from https://www.w3.org/wiki/CSS/Properties/color/keywords

# #7fffd4
# 127,255,212
– id: COLOR_CSS_AQUAMARINE
red: 0.4980
green: 1.0000
blue: 0.8314
white: 0.0000

and so here I went (not without a struggle) from never having taken any notice of YAML to having a working file including embedded C instructions for an ESP32+ILI9341-based board in a matter of days.. I will come across many more bottlenecks but something tells me it will be worth the effort. With MQTT I can integrate this stuff with Node-Red just as I always have but so much display handling is done entiely in the ESP32 itself – and could be in an ESP8266 though my experience to date suggests that the flexibility of ESPHOME means that ILI9341 and similar larger displays may not do so well on the latter (display buffer sizes and RAM)- as you’ll see later however, little OLED displays – no problem. I must stress that I HAVE had the ILI9341 running on ESP8266 using Tasmota.

On the lower part of the code block below – that simple term LAMBDA alows me to continue and achieve display actions in C with which I AM familiar. Again I stress what you see is what you get – ESPHOME + the file below is all there is to it – any libraries are not the concern of the user as ESPHOME handles all of that automatically along with display and sensor initialisation.

My First ESP32 ESPHOME Project – the TTGO Board

esphome:
name: ttgo
platform: ESP32
board: ttgo-t7-v13-mini32
on_boot:
priority: 250
then:
– light.turn_on:
id: LLED
effect: rainbow
# – light.turn_on:
# id: LLED
# brightness: 50%
# red: 0%
# green: 30%
# blue: 100%

packages:
colors: !include color/COLOR_CSS

i2c:
sda: GPIO21
scl: GPIO22
scan: True

sensor:
– platform: bme280
temperature:
name: “BME280 Temperature”
id: bme280_temperature
pressure:
name: “BME280 Pressure”
id: bme280_pressure
humidity:
name: “BME280 Relative Humidity”
id: bme280_humidity
address: 0x77
update_interval: 15s
– platform: template
name: “Altitude”
lambda: |-
const float STANDARD_SEA_LEVEL_PRESSURE = 1013.25; //in hPa, see note
return ((id(bme280_temperature).state + 273.15) / 0.0065) *
(powf((STANDARD_SEA_LEVEL_PRESSURE / id(bme280_pressure).state), 0.190234) – 1); // in meter
update_interval: 15s
icon: ‘mdi:signal’
unit_of_measurement: ‘m’
– platform: template
name: “Absolute Humidity”
lambda: |-
const float mw = 18.01534; // molar mass of water g/mol
const float r = 8.31447215; // Universal gas constant J/mol/K
return (6.112 * powf(2.718281828, (17.67 * id(bme280_temperature).state) /
(id(bme280_temperature).state + 243.5)) * id(bme280_humidity).state * mw) /
((273.15 + id(bme280_temperature).state) * r); // in grams/m^3
accuracy_decimals: 2
update_interval: 15s
icon: ‘mdi:water’
unit_of_measurement: ‘g/m³’
– platform: template
name: “Dew Point”
lambda: |-
return (243.5*(log(id(bme280_humidity).state/100)+((17.67*id(bme280_temperature).state)/
(243.5+id(bme280_temperature).state)))/(17.67-log(id(bme280_humidity).state/100)-
((17.67*id(bme280_temperature).state)/(243.5+id(bme280_temperature).state))));
unit_of_measurement: °C
icon: ‘mdi:thermometer-alert’

# Enable logging
logger:

# Enable Home Assistant API
#api:
# password: “”

ota:
password: “”

wifi:
ssid: “wififorus”
password: “xxxxxxxxx”

# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: “Ttgo Fallback Hotspot”
password: “xni6I5D4VC4m”

captive_portal:

light:
– platform: fastled_clockless
chipset: WS2812B
pin: GPIO32
num_leds: 20
rgb_order: GRB
name: “LLED”
id: LLED
effects:
– addressable_random_twinkle:
name: “twinkle”
– addressable_fireworks:
name: “fireworks”
– addressable_color_wipe:
name: “wipe”
– addressable_rainbow:
name: rainbow

font:
– file: “fonts/digital7.ttf”
id: ubuntuBig
size: 60
– file: “fonts/ubuntu-r.ttf”
id: ubuntuMedium
size: 28
– file: “fonts/ubuntu-r.ttf”
id: ubuntuSmall
size: 14
glyphs: ‘♡ÆØÅæøå!”%()+,-_.:*=°?~#0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz’

binary_sensor:
– platform: status
name: “Node Status”
id: system_status
– platform: gpio
pin:
number: GPIO0
inverted: true
mode: INPUT_PULLUP
name: “T-Display Button Input 0”
id: tdisplay_button_input_0
on_press:
then:
– light.turn_on:
id: LLED
effect: rainbow
on_state:
– component.update: mydisplay

– platform: gpio
pin:
number: GPIO35
inverted: true
name: “T-Display Button Input 1”
id: tdisplay_button_input_1
on_press:
then:
– light.turn_off: LLED
on_state:
– component.update: mydisplay

# Backlight control
switch:
– platform: gpio
pin: GPIO4
name: “Backlight”
id: backlight
– platform: gpio
pin: 17
name: “WiFi LED”
id: wifiLED

#image:
# – file: “image.png”
# id: my_image
# resize: 200×200
# type: RGB24

#time:
# – platform: homeassistant
# id: esptime

time:
– platform: sntp
id: esptime

text_sensor:
– platform: template
internal: true
name: “mydis”
id: mydis

spi:
clk_pin: GPIO18
mosi_pin: GPIO19

mqtt:
broker: 192.168.1.19
username: admin
password: T9quila123
id: mqtt_client
on_message:
– topic: ttgo
then:
– text_sensor.template.publish:
id: mydis
state: !lambda return x;

interval:
– interval: 1s
then:
if:
condition:
wifi.connected:
then:
– switch.turn_on: wifiLED
else:
– switch.turn_off: wifiLED

display:
– platform: st7789v
backlight_pin: GPIO4
cs_pin: GPIO5
dc_pin: GPIO16
reset_pin: GPIO23
rotation: 270
id: mydisplay

update_interval: 1s
lambda: |-
it.rectangle(0, 0, it.get_width(), it.get_height(), id(COLOR_CSS_LIGHTSKYBLUE));
it.rectangle(0, 20, it.get_width(), it.get_height(), id(COLOR_CSS_LIGHTSKYBLUE)); // header bar

if (id(system_status).state) {
it.print(235, 3, id(ubuntuSmall), id(COLOR_CSS_LIGHTGREEN), TextAlign::TOP_RIGHT, “Online”);
}
else {
it.print(235, 3, id(ubuntuSmall), id(COLOR_CSS_RED), TextAlign::TOP_RIGHT, “Offline”);
}
//it.strftime((240 / 2), (140 / 3) * 1 – 10, id(ubuntuMedium), id(COLOR_CSS_ORANGE), TextAlign::CENTER, “%A”, id(esptime).now());
//it.strftime((240 / 2), (140 / 3) * 1 + 20, id(ubuntuMedium), id(COLOR_CSS_SILVER), TextAlign::CENTER, “%d-%m-%Y”, id(esptime).now());

it.rectangle(170, 20, 70, 60, id(COLOR_CSS_LIGHTSKYBLUE));
it.rectangle(00, 20, 171, 60, id(COLOR_CSS_LIGHTSKYBLUE));
it.strftime((205), (140 / 3) * 1 – 10, id(ubuntuMedium), id(COLOR_CSS_ORANGE), TextAlign::CENTER, “%a”, id(esptime).now());
it.strftime((205), (140 / 3) * 1 + 16, id(ubuntuMedium), id(COLOR_CSS_SILVER), TextAlign::CENTER, “%d”, id(esptime).now());

it.filled_rectangle(1, 80, 238, 58,id(COLOR_CSS_YELLOW));
it.strftime((240 / 2), (140 / 3) * 2 + 8, id(ubuntuBig), id(COLOR_CSS_BLACK), TextAlign::CENTER, “%H:%M:%S”, id(esptime).now());
// it.print(5, 3, id(ubuntuSmall), id(COLOR_CSS_YELLOW), TextAlign::TOP_LEFT, “ESPHome”);
it.printf(5, 3, id(ubuntuSmall),id(COLOR_CSS_YELLOW),”%s”,(id(mydis).state).c_str());

if (id(bme280_temperature).has_state())
{
it.printf(5, 25, id(ubuntuSmall),id(COLOR_CSS_GOLDENROD),”BME280 T: %.*f°c”,1,id(bme280_temperature).state);
it.printf(5, 41, id(ubuntuSmall),id(COLOR_CSS_GREENYELLOW),”BME280 H: %.*ff”,1,id(bme280_humidity).state);
it.printf(5, 57, id(ubuntuSmall),id(COLOR_CSS_HOTPINK),”BME280 P: %.*f°hPA”,1,id(bme280_pressure).state);
}

if (id(tdisplay_button_input_0).state==0)
it.filled_circle(155, 40, 6, id(COLOR_CSS_BLUE));
else
it.filled_circle(155, 40, 6, id(COLOR_CSS_HOTPINK));

if (id(tdisplay_button_input_1).state==0)
it.filled_circle(155, 60, 6, id(COLOR_CSS_BLUE));
else
it.filled_circle(155, 60, 6, id(COLOR_CSS_HOTPINK));

// it.image(0, 0, id(my_image));

web_server:
port: 80

Coming Up

I now have an ESP8266 running a Dallas temperature chip (in stainless tube), a set of ws2812b RGB LEDs and an SH1106 128×64 1.2″ OLED display which is my second project having realised that ILI9341 on ESP8266 using ESPHOME isn’t a great idea – I also have project #3, a little ATOM LITE ESP32 board which seems to have some issues with RGB LEDs so that is currently running an SSD1306 128×32 display – on this board I learned how to use PAGES of displays – currently cycled using web page template buttons as I concentrate on developing the pages and my WiFi graphical signal display – ultimately I’ll have the pages self-timed. Ignore the board NAME below – I originally went for an S1351 display…

esphome:
name: s13512
platform: ESP8266
board: nodemcuv2
#on_boot:
# priority: 250
# then:
# – light.turn_on:
# id: LLED
# effect: rainbow
platformio_options:
board_build.f_cpu: 160000000L
# then:
# – light.turn_on:
# id: LLED
# brightness: 50%
# red: 0%
# green: 30%
# blue: 100%

# Enable logging
logger:

switch:
– platform: template
name: “Rainbow”
optimistic: true
turn_on_action:
– light.turn_on:
id: LLED
effect: rainbow
turn_off_action:
– light.turn_off:
id: LLED
– platform: template
name: “Cyan”
optimistic: true
turn_on_action:
– light.turn_on:
id: LLED
brightness: 100%
red: 0%
green: 100%
blue: 100%
turn_off_action:
– light.turn_off:
id: LLED
– platform: template
name: “Magenta”
optimistic: true
turn_on_action:
– light.turn_on:
id: LLED
brightness: 100%
red: 100%
green: 0%
blue: 100%
turn_off_action:
– light.turn_off:
id: LLED

mqtt:
broker: 192.168.1.19
username: admin
password: T9quila123
id: mqtt_client

sensor:
– platform: dallas
address: 0xD000000628016C28
name: “Test Temperature”
id: testtem

dallas:
– pin: GPIO2

# Enable Home Assistant API
#api:
# password: “”

ota:
password: “”

binary_sensor:
– platform: status
name: “Node Status”
id: system_status

wifi:
ssid: “wififorus”
password: “xxxxxxxx”

# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: “SH1106 Fallback Hotspot”
password: “nsa9P6d0UPQR”

#captive_portal:
web_server:
port: 80

font:
– file: “fonts/digital7.ttf”
id: sseg
size: 33
– file: “fonts/ubuntu-r.ttf”
id: tiny
size: 10

time:
– platform: sntp
id: esptime

# Example configuration entry
i2c:
sda: D1
scl: D2

light:
– platform: fastled_clockless
chipset: WS2812B
pin: D8
num_leds: 5
rgb_order: GRB
name: “LLED”
id: LLED
effects:
– addressable_random_twinkle:
name: “twinkle”
– addressable_fireworks:
name: “fireworks”
– addressable_color_wipe:
name: “wipe”
– addressable_rainbow:
name: rainbow

display:
– platform: ssd1306_i2c
model: “SH1106_128X64”
address: 0x3C
lambda: |-
it.rectangle(0, 0, 128, 64);
it.rectangle(0, 0, 128, 16);
if (id(system_status).state) {
it.print(124, 2, id(tiny), TextAlign::TOP_RIGHT, “Online”);
}
else {
it.print(124, 2, id(tiny), TextAlign::TOP_RIGHT, “Offline”);
}
if (id(testtem).has_state())
it.printf(3, 2, id(tiny),”Dallas %.*f°c”,1,id(testtem).state);

it.strftime(3, 18, id(tiny), TextAlign::LEFT, “%A”, id(esptime).now());
it.strftime(124, 18, id(tiny), TextAlign::RIGHT, “%d-%m-%Y”, id(esptime).now());

it.strftime((128 / 2),40, id(sseg), TextAlign::CENTER, “%H:%M:%S”, id(esptime).now());

I’ve had the latter board (LITE + SSD1306) out on the hill above our place running on a USB battery pack to check for range limits and to ensure my signal indicator works (4 simple rectangles, filled or not as needs be by reading an internal value from the YAML code). The other two boards merely say online or offline as appropriate – but in reality I’ve now updates all of them to the graphical indicator).

SH1106 display and ssd1306 display (3 PAGES)

And the code for the smaller SD1306-based board… in the YAML code the hash is a comment line – in the C section, usual C single-line comments apply – but be wary about indents – you can’t put C comments any more left than the code itself – YAML is, it seems as bad as PYTHON for being picky about indents.

esphome:
name: atomlite
platform: ESP32
board: m5stack-core-esp32

mqtt:
broker: 192.168.1.19
username: admin
password: T9quila123
id: mqtt_client

i2c:
sda: GPIO21
scl: GPIO22

globals:
– id: mypages
type: int
restore_value: no
initial_value: ‘0’

# Enable logging
logger:

# Enable Home Assistant API
#api:
# password: “”

ota:
password: “”

wifi:
ssid: “wififorus”
password: “xxxxxxxxxx”

# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: “Atomlite Fallback Hotspot”
password: “OkUUvcffPVMG”

captive_portal:

time:
– platform: sntp
id: esptime

output:
– platform: gpio
pin: GPIO33
id: leds

light:
– platform: binary
name: “mylight”
id: mylight
output: leds

binary_sensor:
– platform: status
name: “Node Status”
id: system_status

sensor:
– platform: wifi_signal
name: “WiFi Signal Sensor”
update_interval: 15s
id: sstrength
– platform: uptime
name: Uptime Sensor
id: upt

web_server:
port: 80

font:
– file: “fonts/digital7.ttf”
id: sseg
size: 26
– file: “fonts/ubuntu-r.ttf”
id: tiny
size: 12
– file: “fonts/ubuntu-r.ttf”
id: teeny
size: 10

switch:
– platform: template
name: “Simple LED”
optimistic: true
turn_on_action:
– light.turn_on:
id: mylight
turn_off_action:
– light.turn_off:
id: mylight
– platform: template
name: “next page”
#optimistic: true – use this if using on_turn_on but turn_on_action seems better.
turn_on_action:
– display.page.show_next: the_display

text_sensor:
– platform: wifi_info
ip_address:
name: ESP IP Address
id: ipaddr
ssid:
name: ESP Connected SSID
bssid:
name: ESP Connected BSSID
mac_address:
name: ESP Mac Wifi Address
id: mac

display:
– platform: ssd1306_i2c
model: “ssd1306_128X32”
id: the_display
address: 0x3C
pages:
– id: page1
lambda: |-
int x=(int)id(sstrength).state;
if (x<0)
{
if ((x>-90) && (x<0)) it.filled_rectangle( 0,14,5,4); else it.rectangle( 0,14,5,4);
if ((x>-70) && (x<0)) it.filled_rectangle( 6,11,5,7); else it.rectangle( 6,11,5,7);
if ((x>-50) && (x<0)) it.filled_rectangle( 12, 8,5,10); else it.rectangle( 12, 8,5,10);
if ((x>-30) && (x<0)) it.filled_rectangle( 18,5,5,13); else it.rectangle( 18,5,5,13);
}

it.strftime(0, 18, id(tiny), TextAlign::LEFT, “%A”, id(esptime).now());
it.strftime(127, 18, id(tiny), TextAlign::RIGHT, “%d-%m-%Y”, id(esptime).now());
it.strftime(127, 0, id(sseg), TextAlign::RIGHT, “%H:%M:%S”, id(esptime).now());

– id: page2
lambda: |-
int x=(int)id(sstrength).state;
it.printf(0,0,id(teeny), “WiFi: %idb”,x);
it.printf(0,10,id(teeny),”Addr: %s”,(id(ipaddr).state).c_str());
it.printf(0,20,id(teeny),”MAC: %s”,(id(mac).state).c_str());

– id: page3
lambda: |-
//it.printf(0,0,id(teeny),”UP: %0.0fs”,(id(upt).state));
int seconds = round(id(upt).state);
int days = seconds / (24 * 3600);
seconds = seconds % (24 * 3600);
int hours = seconds / 3600;
seconds = seconds % 3600;
int minutes = seconds / 60;
seconds = seconds % 60;
it.printf(0,0,id(teeny),”Uptime: %d days, %02d:%02d:%02d”,days,hours,minutes,seconds);

Atom Lite ESPHOME code

If I’ve done anything the hard way around, feel free to tell me how to make a better job. If you don’t understand the code, feel free to ask in here but don’t expect miracles yet – I’m still learning.

On the left you see the web server page generated by the Atom lite – rather handy for testing eithout having to wire up actual buttons – just as well, considering my new discovery that 4 of the ESP32 GPIOS can’t use internal pullups (that kept me going for a while until a kind chat in the ESPHOME forums enlightened me)

And for me the best way to learn is iterative small changes to hardware and software.

Good job I have a constant supply of new boards to test and play with – most of which are on my limited-space desk right now. At this rate I’m going to need a smaller keyboard.

See on the left where it say “next page”? See the SWITCH section above and the platform: template named “next page” – well that controls the pages defined in the display section of the above code.

It’s all a bit of a challenge the first time around but then you quickly get used to the idea, like much of ESPHOME.

AND NOW – the M5Stack Stamp Pico board

I didn’t even bother with other environments for this board (I could have tried UIFLOW or Arduino) – I went straight in at the deep end with ESPHOME.

I picked ESP32 as the target and m5stack-atom as the board, as this was the nearest available option – well – it seems to work.

I repeated steps as earlier, using the ESPHOME wizard and serial port to start the ball rolling, then added:

And then with the PICO board + supplied FTDI (USB-C) plugged into a normal USB charger I was ready to rock – I went to http://stamp.lan on my network… by now I knew how to get my credentials from the SECRETS.YAML file and started to copy over useful functions to the Stamp – but first…

Below, the initial YAML file for the STAMP (which doesnt actually DO anything other than connect to WiFi and show that “stamp Web Server” page) – soon I’ll start pushing this little board to see just what it can do. As it has a few more pins than the Atom Lite – I’m hopeful.

Soon I can see an attempt coming up to run a pair of OLED displays off thge same I2C – pins – it should be possible to change the default address od 3C to 3D easily enough – it remains to be seen if ESPHOME handles this or not.

Time will tell.

esphome:
name: stamp
platform: ESP32
board: m5stack-atom

# Enable logging
logger:

ota:
password: “”

wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: “Stamp Fallback Hotspot”
password: !secret wifi_password

mqtt:
broker: !secret mqtt_broker
username: !secret mqtt_user
password: !secret mqtt_password
id: mqtt_client

captive_portal:

web_server:
port: 80
Facebooktwitterpinterestlinkedin