TheGreydiamonds Blog

Tag: esp32

Just another Bindicator

While mindlessly scrolling Reddit, I found a project on the r/homeassistant subreddit which piqued my interest. A bin indicator (or indicator for short) that lit up a miniature wheelie bin whenever it is time to take out the trash. Taking inspiration from Dean Fourie’s Bindicator I set out to make my one.

The very first step was to find a wheelie bin model I liked. After scouring platforms like Thingiverse and Makerworld, I settled on this model by “JAV-3D” as it resembled our bins the most. I’ve printed it on my Bambu Labs A1 using white silk filament.

Using the basic tools BambuStudio provides, I added a hole for the USB-C plug to fit through as a last-minute addition.

Brainnnsss…

Next came the more interesting part, the heart and soul of this project: the electronics! I’ve opted to use an ESP32-S3-Zero made by Waveshare for two reasons:

  • I had it lying around
  • It features an integrated WS2812 pixel

This reduced the amount of extra hardware I needed. The only other thing I added was a bit of enamelled copper wire to GPIO 5. This will serve as a touch button which works through the lid of the bin. When you tap the top, the light will dim down to show that you have “acknowledged” the notification (aka you brought the trash out).

As I’m already actively using Home Assistant for my smart home, it made sense to opt for ESPHome as my firmware base. I used the online tool for flashing ESPHome. and commissioned it into my network. The configuration is fairly straightforward:

esphome:
  name: esphome-bindicator
  friendly_name: ESPHome Web - Bindicator
  min_version: 2025.5.0
  name_add_mac_suffix: false

esp32:
  board: esp32-s3-devkitc-1
  framework:
    type: esp-idf

# Enable logging
logger:

# Enable Home Assistant API
api:

# Allow Over-The-Air updates
ota:
- platform: esphome

web_server:
  port: 80

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Enable fallback hotspot if WiFi connection fails
  ap:

light:
  - platform: esp32_rmt_led_strip
    rgb_order: RGB
    pin: GPIO21
    num_leds: 1
    chipset: ws2812
    name: "Binlight"
    id: "binlight"
    effects:
    - pulse:
        name: "Blink Fast"
        transition_length: 250ms
        update_interval: 250ms
        min_brightness: 8%
        max_brightness: 100%

    - pulse:
        name: "Blink Slow"
        transition_length: 2s
        update_interval: 2s
        min_brightness: 40%
        max_brightness: 100%

esp32_touch:
  setup_mode: false
  measurement_duration: 0.25ms  # Much lower than the 8ms default
  sleep_duration: 0.5ms

binary_sensor:
  - platform: esp32_touch
    name: "Binlight Ack Btn"
    pin: GPIO5
    threshold: 1000

This config uses the esp32_rmt_led_strip component to drive the pixel internally connected to GPIO21, and adds two effects. It also initialises the touch component. If you use a different ESP32 board, I recommend you check the touch component documentation. I needed to change some values for it to work at all.

Home Assistant Integration

Now, only one component was missing: The collection schedule data. My local waste collection company is supported by the awesome “Waste Collection Schedule” integration for Home Assistant. I only care about two kinds of garbage: paper and packaging (“gelber sack” = “yellow trash” in German). For each, I configured a sensor with this config:

Format: Next
Value Template: {{value.daysTo}}
Type: “Papierabfall” (or whatever you want)

Last but not least, I created a new automation. My triggers were quite simple:

Two time triggers (“update” times) and a trigger for handling the acknowledgement.

The logic was a little more complex. When it is time to update the state, I check which trash type is next (or if both fall on the same day) and turn on the light accordingly. If both types are more than 2 days away, the light gets simply switched off.

When the touch button gets triggered, I dim the indicator to 30% (only if it was on in the first place)

Final result

After an afternoon of tinkering, I was happy with my result. Let me know down in the comments if you have something similar for your smart home! Now enjoy a few photos and a video demo of the final result:

Learn more about my Smarthome projects

Sending, Receiving and verifying messages sent over LoRa using RFM95W

In this blog post, I will be using an RFM95W LoRa chip together with an ESP8266/ESP32 to transmit (receive/send) data and check if this data is complete.

Preperations

My first course of action was to get two ESPs ready to send/receive data via LoRa. If you have trouble or are looking for a dedicated tutorial have a look at these posts for the ESP32 and ESP8266. I have decided that my ESP8266 will send data and my ESP32 receive this data.

As a simple first test, I used the provided example sketches. This worked pretty well, I received my packets on the ESP32. After looking at it for a while I found a problem: RF has (like everything else) the problem of packet corruption, it doesn’t happen very often but when it does, it gets annoying.

The Problem

Our main problem is data corruption, my goal for this is to detect data corruption and ignore the received message. Let’s take an example: You have a simple LoRa node connected to a motion sensor, we send a data packet containing the battery state and the motion sensor’s state, like so:

0;1

The zero being the motion state (0, meaning false / no motion), and the 1 being the battery health (1, meaning true / healthy). Now let’s imagine there is a packet corruption and the first part (0;) gets removed, now our first item is a 1. If the receiver doesn’t notice the broken package, it might be that a false alarm gets triggered. After all the first bit, so motion, was true. This is the reason we need to check if a package is actually healthy.

My idea was to send the data and append some kind of hash to it. I will be using a sha1 hash for this, as ESPs can calculate this hash pretty easily, even though it’s a little overkill for this application. My new package will now look like this:

Actual data here;hash
Hello 4;a94a8fe5ccb19ba61c4c0873d391e987982fbbd3

Okay, after making the theory clear let’s implement it!

The implementation

Starting with my sending code, it looks like this:

Use the right frequencies for your region

If you adapt this code please check if you use the right frequency. Different regions use different frequencies for LoRa. Please check your local guidelines. Europe uses 868MHz (868E6). Update your LoRa.begin line! Here is a useful table by TTN.

#include <SPI.h>
#include <LoRa.h>
#include "Hash.h"

int counter = 0;
// - Pin configs - ESP32 -
// #define ss 5
// #define rst 14
// #define dio0 2

// - Pin configs - ESP8266 -
#define ss 4    // D2
#define rst  5 // D1
#define dio0 -1 // Disabled



void setup() {
  Serial.begin(115200);
  while (!Serial);
  delay(1000);

  Serial.println("LoRa Sender");
  // Setup LoRa transceiver module
  LoRa.setPins(ss, rst, dio0);
  if (!LoRa.begin(868E6)) {
    Serial.println("Starting LoRa failed!");
    delay(5000);
    Serial.println("Now waiting for Watchdog to restart");
    while (1);
  }else{
    Serial.println("Starting LoRa successful");
    }
  
}

// Sends a string every 5000ms (5 seconds)
void loop() {
  Serial.print("Sending packet: ");
  Serial.println(counter);

  // send packet
  LoRa.beginPacket();
  String result = sha1("hello " + String(counter)); // Creating the hash value for our string
  LoRa.print("hello ");
  LoRa.print(counter);
  LoRa.print(";");
  LoRa.print(result);
  LoRa.endPacket();

  counter++;

  delay(5000);
}

This will send our packets with the hash appended. For the next bit, we will need to receive the message and check if the supplied hash is correct.

#include <SPI.h>
#include <LoRa.h>
#include <Hash.h>
// - Pin configs - ESP32 -
#define ss 5
#define rst 14
#define dio0 2

// - Pin configs - ESP8266 -
// #define ss 4    // D2
// #define rst  5 // D1
// #define dio0 -1 // Disabled

// Taken from https://forum.arduino.cc/t/arduino-split-funktion-eines-strings/595753
String split(String s, char parser, int index) {
  String rs = "";
  int parserIndex = index;
  int parserCnt = 0;
  int rFromIndex = 0, rToIndex = -1;
  while (index >= parserCnt) {
    rFromIndex = rToIndex + 1;
    rToIndex = s.indexOf(parser, rFromIndex);
    if (index == parserCnt) {
      if (rToIndex == 0 || rToIndex == -1) return "";
      return s.substring(rFromIndex, rToIndex);
    } else parserCnt++;
  }
  return rs;
}

void setup() {
  Serial.begin(115200);
  while (!Serial);

  Serial.println("LoRa Receiver");
  LoRa.setPins(ss, rst, dio0);
if (!LoRa.begin(868E6)) {
    Serial.println("Starting LoRa failed!");
    delay(5000);
    Serial.println("Now waiting for Watchdog to restart");
    while (1);
  }else{
    Serial.println("Starting LoRa successful");
    }
}

void loop() {
  // try to parse packet
  int packetSize = LoRa.parsePacket();
  if (packetSize) {
    // received a packet
    Serial.print("Received packet '");

    // Create a string of the incoming message
    String message = "";
    while (LoRa.available()) {
      message += (char)LoRa.read();
    }
    Serial.print(message);
 
    String result = sha1(split(message, ';', 0)); // Take the first element, the raw message and hashing it
    String tempy = message;
    tempy.replace(split(message, ';', 0) + ";", ""); // Now replace the message so only the hash is left
    if (result == tempy) { // Is the hash the same?
      Serial.print(" Hash ok ");
    } else {
      Serial.print(" Hash fail, expectd hash ");
      Serial.print(tempy);
      Serial.print(" "); 
      Serial.print(split(message, ';', 1)); 
      Serial.print(" "); 
    }

    // print RSSI of packet
    Serial.print("' with RSSI ");
    Serial.println(LoRa.packetRssi());
  }
}

Using the hash library on ESP32

For some reason, the ESP32 does not implement the same hash functions as the ESP8266. Therefore I used this third party library to get the same functinality.

After running the code for a while I got this output on my receiver serial console. It worked! Sadly it’s pretty hard to break a package on purpose, but I checked it and this code works, however, I sadly don’t have a screenshot of a broken transmission.

This concludes my little experiment/project here, I have achieved my goal to detect broken transmissions and that’s it! I hoped this helped someone on their way.

Getting started with RFM95W, LoRa and ESP32

In this blog post I will be introducing you to LoRa using the RFM95W module with an ESP32, so let’s get started. I also wrote a tutorial for the ESP8266.

First, we should talk about what LoRa is and what it stands for. LoRa stands for Long Range and as the name suggests one of its main aspects is its considerable range. However, we need to make a distinction between LoRa and LoRaWAN. In this tutorial, I will be talking about LoRa. LoRaWAN adds another layer of authentification. Services like TheThingsNetwork (TTN) use LoRaWAN. However, LoRa is easier to use and understand for this tutorial.

Hardware used / Preparation

For this tutorial, I will be using an RFM95W module with an ESP32. The RFM95W is our LoRa communication chip. I’ve got my ESP from the german seller AZ-Delivery (I’m not affiliated with them in any way nor do I get any money from them for mentioning their name). My RFM95W comes from Amazon.

For this, I will assume that your Arduino IDE is set up to work with ESP32s. If not here is a tutorial to do it.

Wiring

The wiring diagram

If you have a different ESP you can check the documentation supplied below for further details.

Now get started, for real

As a first step build up the setup shown above. Next, you need to install the LoRa Libary by Sandeep Mistry. More documentation is available here.

This code is actually the library’s example code modified to give a little more output.

Use the right frequencies for your region

Different regions use different frequencies for LoRa. Please check your local guidelines. Europe uses 868MHz (868E6). Update your LoRa.begin line!

#include <SPI.h>
#include <LoRa.h>

int counter = 0;
// - Pin configs -
#define ss 5
#define rst 14
#define dio0 2

void setup() {
  Serial.begin(115200);
  while (!Serial);
  delay(1000);

  Serial.println("LoRa Sender");
  // Setup LoRa transceiver module
  LoRa.setPins(ss, rst, dio0);
  
  if (!LoRa.begin(868E6)) {
    Serial.println("Starting LoRa failed!");
    while (1);
  }else{
    Serial.println("Starting LoRa successful");
    }
  
}

// Sends a string every 5000ms (5 seconds)
void loop() {
  Serial.print("Sending packet: ");
  Serial.println(counter);

  // send packet
  LoRa.beginPacket();
  LoRa.print("hello ");
  LoRa.print(counter);
  LoRa.endPacket();

  counter++;

  delay(5000);
}

I’ve had some issues using the code out-of-the-box. Some problems are due to the code lacking a lot of verbosity and some are due to user problems. The code above fixes one of the issues, verbosity. The other one is addressed below.

Tip

While trying to get this running I’ve run into an issue where the code returned “Starting LoRa successful”, however, no data got sent. Make sure to use the correct board, check with your manufacturer what board you should use. Different boards have different pinouts.

After changing your frequencies and making sure that you use the right board, hit the upload button. After the upload is done open your serial console, select 115200 baud. Then you should see this output:

A arduino serial output window.
The serial output

And finally, your ESP is sending LoRa. Some of the items I need for receiving are stuck in shipping this has to wait for another day. However, below is a short paragraph for those who already own an SDR.

Does this even work? For people with SDRs

This paragraph is made for people who own SDRs (SoftwareDefinedRadio). For this, I’m using a VM running ParrotOS. This image comes preinstalled with SDR++. GNUradio and a bunch of extensions for GNUradio. These extensions also contain gr-lora, which I will be using here. Following this tutorial in the wiki, you should be able to set up your workspace to receive LoRa messages. Please also remember to use the right frequency. The results looks something like this:

With this setup, I was able to use a pretty good range, even though I only used a so-called random wire antenna. This also shows how some packets are missing some data. This shows why you should always use the hash numbers to verify that the received packet is healthy. I will be talking about hashes sometime in the future.

The result as seen in SDR++

I hope I could get you on your way into the interesting world of LoRa.

© 2025 Thegreydiamond

Theme by Anders NorenUp ↑