Skip to main content

Battle of BLEtain



The trolling. The doxing. An army of perplexing emojis. And endless links to the same - supposedly funny - viral video of a cat confusing a reflection from a dangling key for a golden hamster, while taking part in the mice bucket challenge. Has social media really been this immense force for good? Has it actually contributed significantly to the continued enlightenment of the human (or feline) race?

In order to answer these poignant existential questions about the role of prominent platforms such as Critter, StinkedIn and Binterest, employing exceptional scientific rigour equal to that demonstrated by Theranos, we're going to set up a ground-breaking experiment using the Bluetooth Low Energy feature of MicroPython v1.12, and two ESP32 development boards with inexplicable hatred for one another.  And let them hurl quintessentially British expressions (others call them abuse) at each other like two Wiltshire residents who have had their internet access curbed by the county judge as part of their ASBO. In short, they are about to resort to the use of a commonly used wireless personal area network technology to continue their never-ending crusade to irritate as many of their compatriots as possible with the ™BLUEtruth™, without ever having to make eye contact. Or leave the comfort of their half-price DFS sofas.

So here's our totally "legitimate" opinion (that you never asked for) on a topic that we know nothing about. VOICED WITH SUCH CONVICTION AND AUTHENTICITY (IN MANDATORY CAPITALS) that we might just come to believe in the %&"£ spewing out of our mouths ourselves.

...Because it looks like Van Damme is back as the furious keyboard bashing pensioner with some interesting opinions and somewhat more dubious conspiracy theories... in Blogsport 5: The Last Marmite. And we have an overdramatic story (about something that probably never happened) to tell. And, unfortunately for our readership, it will take more than the 280 characters to tell it.

A (Python) thread.

*The Terms of Use: This article now contains a totally unnecessary rant on Real-Time Clocks. And we will totally harvest all your personal information, and sell it to the highest bidder for monetary gain. No seriously. Like, all of it.*

Reddit Dead Redemption:

Sure, you will first need to scroll through our timeline infested by pushy ads about 2-for-1 offers on cute foxes named James because you might have once mistyped the Sleepless actor into a search engine. Well, then. You won't mind some more.


Here's our flashy gift ideas, extrapolated from your sordid search history. Right in time for Valentine's Day fortnightly refuse collection. Except you are right to feel short-changed, as there's probably just 2 here. And - let's be honest - the rest is just clickbait.

  • Here's the first: an ESP32 development board, running MicroPython.  We're in fact using a HelTec Automation Wireless Stick, not because we need to make use of its LoRa capabilities, but because we happen to have one lying around. It has a built-in 0.49 inch 64×32 OLED display, and I2C and - crucially - Bluetooth Low Energy support, via the venerable, cheap-and-cheerful ESP32 microprocessor. Later, we invite another ESP32 development board into this members-only forum, because the fast and furious, zero-sumpal game of anti-social media just can't be played alone.
  • Another commodity that everyone publicly broadcasting their opinions appear to have in abundance is... time. LOTS of it. Like, pretty much 27 hours of it a day. OK, then, let's get our hands on some of this time ourselves. This will be our first encounter with a DS3231 Real-Time Clock. Or, more accurately, a handy module housing the DS3231 chip.  It can be interfaced using I2C, and has a slot for a CR2032 battery to enable it to carry on timekeeping, even when our ESP32 development is no longer powered. Or the world has been obliterated by nuclear weapons after a rather rowdy Twitter spat.

So sure, we don't actually have that much kit here to brag about. But we will anyway. Because we are self-centred egomaniacs in possession of a smartphone equipped with 10 petapixel front and rear cameras. And we're prepared to use them on the end of a selfie-stick the height of Tower Bridge.


It's all on our Blog-ergh:

Check out the 15-second parasitic nuisance we have just posted on TickTick! Do please watch us carelessly obliterate a helpless development board on Wastebook Live! And feel free to come smell the nauseatingly ammonic stench of startup success in our WeeWork offices!

...But because we don't actually use any of the aforementioned services to undertake our adventures (yet), you will have no alternative but to laboriously click your way through the shameless, promotional links splattered out below in the current thread: I-O-Mr-T.

  1. Gold Filing
  2. Castle Track-a-lot
  3. Chariots of Wire
  4. Athlete's Foot
  5. SD:S3 The Untold Love Story
  6. Rage:MKR

But, wait. What's this unexpected banner that you see distracting you in the middle of this post?!

!!!YOU HAVE BEEN RANDOMLY CHOSEN (FOR NO REASON WHATSOEVER) TO RECEIVE $12,000,000. CLICK THIS SUSPICIOUS LOOKING LINK IN THE MIDDLE OF A COMPLETELY UNRELATED BLOG POST TO CLAIM THE MONEY!!!

You can follow us on Twitter, however! Here's a less suspicious-looking button to prove it.



I just Skype-called, to say, I dab glue:

Makers, What's Ughpp? Here's the rad agenda we have just posted on EventByte for this digital electronics hackathon which has approximately 0 people interested in attending (but who we'll charge for not attending anyway because we have a group going on MeetUp).

  • We'll flash our ESP32 development board with the latest and greatest:- MicroPython v1.12. And test that we can do some basic stuff with it, like show-off our tiny OLED screen. Using all sorts of unnecessary Snapchat filters.
  • We'll then proceed to set the time on our DS3231 Real-Time Clock using I2C, and make sure that we can retrieve time back from it even after our microprocessor restarts after a little afternoon snooze (yes, vilifying everyone and anyone, except yourself, is real hard work).
  • We will make a simple clock at this point, only to demonstrate the workings of our RTC. And swiftly put it up for sale on Etsy for £3000 under the Arts and Collectibles section.
  • And lastly, we familiarise ourselves with the high level workings of Bluetooth Low Energy on MicroPython. Using it, we'll emulate the efficient manner in which insults can be lobbed at one another across social media platforms using this prevalent wireless personal area networking technology.

Sure, we won't be dabbing any epoxy glue onto some helpless 3D print in this episode. Or - staying true to the social networking ethos - doing anything, actually, that requires us to move away from the screen. Like meeting people in real life. In other words, being social. Or doing any networking.

But worry not, because it's all about the virtual likes.

Read our ME!dium:

We have concluded that this post is a highly partisan affair, with two competing tribes fighting for our attention: those that think this post should keep it conservative and be solely about the good ol' RTC, and those that think it should pursue the progressive, radical Bluetooth Low Energy agenda.

Simply put, Real-Time Clocks (RTC) are used to keep track of time. And the ESP32 has a built-in (internal) RTC. So what's the problem? Well, if we frequently power off and on our ESP development boards (which we do), then power to the internal RTC is lost, and its time resets itself. And if we're talking about 2 ESP32 development boards about to (unwillingly) undertake a digital detox from the internet, we can't synchronise the internal RTC back to "real world time" using Network Time Protocol. Nor using GPS, if we don't have a GPS receiver. Without timestamps that are aligned to the outside world, logging time-dependent data "offline" on IoT devices becomes a challenge.

This is why many electronic goods have self-sufficient, battery powered Real-Time Clocks - that once set - can continue to timekeep for "many years" to come. And the microprocessor can simply interrogate it when it starts up by synchronising its own internal RTC to it. The DS3231 Real-Time Clock is one such device.

Bluetooth Low Energy on the other hand is a lightweight cousin of Bluetooth, and as the name implies, it is a wireless personal area network technology which is designed to consume as little power as possible. Using BLE, peripherals (such as sensors) can exchange data with a central device in close proximity (such as computers or phones). MicroPython v1.12 officially introduced support for BLE through the ubluetooth built-in module. Which means it is as good a time as any to try it out.

Word War 00000011:

Do we want to get our hands on MicroPython v1.12? Sure we do. Let's download the MicroPython v1.12 ESP32 firmware from the download page (while being careful to select the version with BLE support).

Sure, we know how to flash ESP32 development boards with new firmware. But here's a simple recap.

esptool.py --port COM3 --baud 115200 erase_flash


Once the previous firmware has been erased, we can flash it with our new v1.12 ESP32 firmware.

esptool.py --port COM3 --baud 115200 write_flash -z 0x1000 esp32-idf4-20191220-v1.12.bin


Quick check of the version, and we're good to go.

import os
os.uname()


It's always a guilty pleasure to drive a connected OLED screen using the MicroPython SSD1306 driver. Here's a reminder on how to do this, using the I2C protocol. The pinouts here are specific to our HelTec Automation Wireless Stick, so we'd need to change the pins (and OLED size) accordingly when used with other devices.

from machine import I2C, Pin
import ssd1306

reset = Pin(16, Pin.OUT, value=1)
scl_pin = Pin(15, Pin.IN, Pin.PULL_UP)
sda_pin = Pin(4, Pin.IN, Pin.PULL_UP)
i2c = I2C(scl=scl_pin, sda=sda_pin, freq=400000)
oled = ssd1306.SSD1306_I2C(64, 32, i2c)
oled.text("Hello MP", 0, 16)
oled.text(" v" + os.uname()[2][:4] + "! ", 0, 24)
oled.show()

# Clear the screen afterwards
oled.fill(0)
oled.show()

So far so good. It's as good a time as any to stop and ask for instant online validation of our purpose in life by posting an artistic #nofilter snap of our bling. Ready? Snap!


Now, we can swiftly move onto to the RTC.

Ours can be powered by a CR2032 button cell battery. Which is kinda important, since it needs to independently keep track of time.

At a minimum, the standard set of I2C wires are required to interface with it, for which we're sharing same I2C bus as the OLED (SCL: 15, SDA: 4). Other pins are available, if you need the RTC to do more than just keep track of time (i.e. supply an alarm or a SpongeBob Square Wave).


We scan our I2C bus and - hey presto! - we can see our new address(es) for the DS3231.

i2c.scan()


This is where it gets a little more interesting. Unless we want to hand enter the current data / time, it is best to temporarily connect the ESP32 development board to the internet via Wi-Fi which will allow us to use ntptime.settime() to perform a one time synchronisation of the internal, onboard RTC to an internet NTP source.

import network
sta_if = network.WLAN(network.STA_IF)
sta_if.active()
sta_if.active(True)
sta_if.connect("mywonderfulSSID", "mynotsowonderfulPassword")
sta_if.isconnected()
sta_if.ifconfig()
# Disable access point
ap_if = network.WLAN(network.AP_IF)
ap_if.active(False)

All connected to our local wireless network? Good.

In short, whenever the ESP32 development board loses power, it resets its time to the year 2000. The ntptime.settime() allows us to reset it to the actual time, using the powers of NTP. But since our ESP32 will be offline for a while, we commit this back to the DS3231 using the MicroPython ds3231 library's save_time() method.

import utime
from ds3231_port import DS3231
from ntptime import settime
# Microprocessor time reset after power loss
print(utime.localtime())
# Use NTP (one time only) to set time and save back to DS3231
# Code here to connect to local Wi-Fi network
settime()
print(utime.localtime())
ds3231 = DS3231(i2c)
ds3231.save_time()

As the DS3231 RTC is now set, and is happily time-keeping independently of our ESP32 development board, we can simply retrieve the current time from it and set our internal ESP32 RTC using get_time(set_rtc=True) after any restarts (without relying on an available Wi-Fi connection).

# At subsequent system startup, retrieve time from DS3231 and set system time
print(utime.localtime())
ds3231.get_time(set_rtc=True)
print(utime.localtime())


It's worth noting that this method only remains valid while the RTC itself remains powered by the battery. The battery runs out, or is removed, and we would have to set the RTC's time again. RTCs can also drift over time as well (DS3231 by apparently up to ±110 seconds a year), so it should probably be checked periodically and brought back under control if our application is time-sensitive.

The end to end process can be demonstrated as a simple ESP32 clock application that continues to show its correct time even after it has been restarted.


Here's the code snippet used to achieve this.




Just by checking the DS3231 datasheet, it is clear that RTCs can do other useful stuff too. Like set alarms. Or output a square wave. All very useful features if we had reasons to rely on this external RTC for the majority of our timing needs.

We've noticed the other half of our audience getting restless. It's time therefore to move onto the magic of Bluetooth Low Energy.

We have two eager social media warriors located in a nondescript English housing development that ordinarily shares little else than a local Co-Op store. Their BLEchat! profiles introduce themselves as "knowitall24" and "loudmouth868", but they are probably called Brenda and Terry from Swindon. And they are likely to have just put their grand kids to bed, fed the cats and watered the garden... so are ready for some good-old fashioned online skirmishes.


Their heated exchange will be as nonsensical, as it will be short-lived and - ultimately - pointless. But let's not waste any more time in the real world.

  • "loudmouth868" will configure itself with BLE UART services using the ubluetooth library, and valiantly advertise itself out to the immediate vicinity to instantly become the target of ridicule and criticism.
  • "knowitall24" - after a heavy night on tins of Carling - will discover "loudmouth868" and proceed to connect to it over BLE. After all, you can't call it a smashing night, without engaging in some mindless debates online with a person that you are never going to meet (but probably lives next door).
  • Once connected via BLE, "knowitall24" will discover the UART services running on "loudmouth868" and obtain connection parameters for it.
  • The scene is now set for some quality BLEChat! action that should never have to take place, and with which future forensic anthropologists from another universe should evaluate the human race's collective intelligence.

The ubluetooth library is centred around its event handlers. Every time a BLE event is triggered, we need to check what type of event it is, and respond to it accordingly. The list of events are documented in the library's documentation, but here's the short script we use on both ESP32 development boards to setup our event handlers.

Note that only the peripheral needs to have UART services registered, a task currently undertaken by our crude register_services() function (which in turn runs the ble.gatts_register_services() method which configures services with the Nordic UART UUID).  After BLE is activated - ble.active(True) - and event handler started - ble.irq(handler=ble_irq) - we are ready to start talking.

On our peripheral, we advertise out our willingness to engage in some mindless chitchat by using ble.gap_advertise().

register_services()
adv_data = "loudmouth868"
ble.gap_advertise(100, bytearray("\x02\x01\x02") + adv_encode_name(adv_data))

Back on the central device, we can now scan the environment using ble.gap_scan() to see if we can detect our social media adversary:

adv_data = "knowitall24"
ble.gap_scan(10000)

RELEASE THE KRACKIN'... (SPLIT SCREEEEEENS!)

There it is. Device found (and it has a semi-legible BLE address of b'<q\xbfky\xc6'). We're ready to proceed.


The next step is to connect to our peripheral device (which we know to have address of b'<q\xbfky\xc6'), from the central using ble.gap_connect().

ble.gap_connect(0, b'<q\xbfky\xc6')

Once connected, we can use ble.gattc_discover_services() to discover the services registered on that peripheral (we learn, for example, that the UART service has start and end handles of 11 and 65535). And equipped with this information, we can use ble.gattc_discover_characteristics() to retrieve the UART service's value handles from the peripheral.

ble.gattc_discover_services(0)
ble.gattc_discover_characteristics(0, 11, 65535)

We need these details to know how to communicate with this specific peripheral. We recognise these value handles, because these are the transmit (13) and receive (16) value handles that were registered during service registration on the peripheral.


Now that we have confirmed that a UART service is running on the peripheral, and know its value handles for transmit and receive of serial data, we can start to exchange messages.

Central can write to a peripheral using the ble.gattc_write() method. This data can then be retrieved on the peripheral using ble.gatts_read().

# Using write (on central)
ble.gattc_write(0, 16, "Hey, you plonker!")
# Read manually (on peripheral)
ble.gatts_read(16)

The peripheral can also write back to central using the ble.gatts_write() method. Notice how central needs to run ble.gatts_read() to retrieve this value. However, there is also a similar ble.gatts_notify() method, which is handy as it immediately notifies central of the value.

# Using write (on peripheral)
ble.gatts_write(13, "You inglorious twit!")
# Read manually (on central)
ble.gattc_read(0, 13)

# Or using notify (on peripheral)
ble.gatts_notify(0, 13, "You must be plastered again!")


Clearly, by adding more code into the body of the event handlers, we could automate much of this (our script above currently only prints the data returned by the event on the screen). For example, once we connect to a peripheral, we could go on and discover its services and characteristics. Similarly, on the peripheral, we could initiate a ble.gatts_read()immediately after a _IRQ_GATTS_WRITE event has been triggered, and respond accordingly. Which is sort of how we end up demonstrating this below.

But that is more about the cohesiveness of the entire application, rather than how to engage in pointless conversations with an unfriendly neighbour using BLE. We have all the basics now covered to participate in the exchange of data.


In a typically British fashion, these verbal salvos will be mild, and well-mannered, by international standards. Fear not, educators. Your schoolchildren are allowed to proceed on to the content beyond this point denoted by the sacred Scratchy Bottom stone. Trust us! Because we're bona fide social media effluencers.


Here are two not too dissimilar ESP32 development boards arguing with one another. Over BLE. Now that you've seen this, you've quite literally seen everything. Except you haven't, because this is only the 7th instalment in our current blog series about achieving technological milestones of questionable value: I-O-Mr-T. And as you probably know, our entire site has now been going on for over 2 and a half years.


Clearly, Bluetooth has so many more facets not explored here. For example, there are countless other profiles, other than just UART. There are other BLE capabilities such as pairing, and beaconing. If you so wished, you could spend your weekend reading the official Bluetooth Specifications (yes, 3000+ pages of it), instead of bashing other netizens semi-anonymously with your best insults.

This concludes our farcical attempt at recreating the realities of modern day social media... using the (low)powers of Bluetooth Low Energy. Sure, it hasn't made a billionaire of us. Nor has it presented us with any opportunities to sell your data to Cambridge Analytica, intelligence agencies, or... well... anyone who wants it really. But - for now - we can sleep easily knowing that we have become acquainted with some pretty useful tech that we seemingly encounter on a daily basis without us necessary noticing. And we can incorporate them into our next project(s).

But more importantly, we have two development boards that have managed to air their grievances that ought to have made their way to ShredIt, rather than Reddit. All without leaving the comfort of their own homes. Perhaps, that is the point after all. That battles fought online, don't generally get fought offline. And the real world is better off because of it..?

Now, dear readers, on that calming, uncharacteristically philosophical note, we have one last parting announcement to make.

Shut your big gob and vacate our daft blog, you complete nutter!

Terms and Conditions:

As always, ESP32 MicroPython firmware downloads are available here:
We're using the MicroPython SSD1306 driver, because sometimes you just have to see it for yourself on a screen to believe it:
Not that it's very important to this experiment, we're using a HelTec Automation Wireless Stick:
...For which the Wireless Stick pinout diagrams can be found here:
The all important MicroPython uBluetooth library is available below:
Rummaging through this MicroPython uBluetooth PR provided some guidance on how to actually use this thing (because it wasn't immediately obvious):
Just in case you have some time before bed. Here's the Maxim Integrated DS3231 RTC datasheet:
...And we've used this MiroPython DS3231 RTC library to make use of it.

Comments

MOST VISITED (APPARENTLY)

LoRa-Wan Kenobi

In the regurgitated words of Michael BublĂ©: It's a new dawn .  It's a new day .  It's a new Star Wars film .  For me .  And I'm (George Lucas, and I'm) feeling good .  Unfortunately for Canadian Mike, the Grammy that year was won by the novelty disco classic with the famous refrain: We love IoT, even in Planet Tatooine * . *Not true. Clearly, the Star Wars producers didn't sincerely mean the last Jedi the previous time around.  Return of the Jedi, released during the decade that spearheaded cultural renaissance 2.0 with the mullet and hair-metal , was less economic with the truth.  Either way, we're going to take inspiration from the impressive longevity of the money-spinning space-opera and reboot our franchise with some Jedi mind tricks.  Except this particular flick doesn't require an ever-growing cast of unrecognisable characters, unless ASCII or UTF counts.  In place of an ensemble gathering of Hollywood stars and starlets, we will b

Hard grapht

You would all be forgiven for assuming that bar , pie and queue line are favourite pastimes of the British .  Yet, in fact – yes, we did learn this back in GCSE maths – they are also mechanisms through which meaningless, mundane data of suspect origin can be given a Gok Wan -grade makeover, with the prime objective of padding out biblical 187-page PowerPoint presentations and 871-page Word reports (*other Microsoft productivity tools are available).  In other words, documents that nobody has the intention of ever reading.  But it becomes apparent over the years; this is perhaps the one skill which serves you well for a lifetime in certain careers.  In sales.  Consultancy.  Politics.  Or any other profession in which the only known entry requirement is the ability to chat loudly over a whizzy graph of dubious quality and value, preferably while frantically waving your arms around. Nevertheless, we are acutely conscious of the fact that we have spent an inordinate amount