Skip to main content

Bruce's Site is Wise

Bruce is a proud, hard-working factory owner of the traditional ilk. He inexplicably owns a nondescript, prefabricated concrete building on the outskirts of Swindon equipped with a good-fashioned conveyor belt which certifies him as a respected industrialist. The true beating heart of the British economy. An employer of many (or, actually, none). Nobody knows what his corporation makes, although curious locals have noticed late night arrivals of articulated lorries, and a mountain of discarded Cadbury wrappers and 2 litre bottles of Sprite.

So what keeps Bruce awake at night (apart from the diet of sugar)? When door-stepped during a Panorama special - Britain's Shady Entrepreneurs: Living the Creme - by an investigative reporter from BBC West, he coyly replied that it is this:

How do I - Bruce, an upstanding member of the community - "collect, store, organise and monitor data from my industrial equipment at scale"? ...And we categorically deny all accusations that we produce fake Cadbury egg products. Not that you asked. But if you had... **universal stop the camera sign**

Well today's your lucky day, Bruce, because we can address one of your pain points (the other, is likely to require a good lawyer at 10 times the hourly rate of an i3en.metal on-demand EC2 instance). Your prized conveyor belt can be safe from the eerie going-ons on the illegal confectionery factory floor at night. Because here's an AWS IoT service that allows you to "collect, store, organise and monitor your industrial equipment at scale".

Cue the obligatory screenshot with highlighted text to allude that *some* research may have been undertaken on this subject.

Ladies and gentlemen. Hands on buzzers please. It's time to play a round of Bruce's Site is Wise.

£10 Bill O'Materials:

Since we plastered a screenshot of this particular AWS IoT service upfront, and dubiously created an entire narrative (and graphic) around it, we're clearly going to use AWS IoT SiteWise to report on the status of our things. That much is clear.

But what else do we need to do to make Bruce's mysterious Wiltshire factory - quite literally - come alive?

  • Aha! Its documentation tells us that SiteWise can receive data from our industrial equipment using OPC Unified Architecture (OPC-UA) servers, APIs or using bog standard AWS IoT Rules. Let's whip out our Raspberry Pi running Greengrass Core - not because we are going to run OPC-UA - but because we want to continue to use it as our local edge gateway to our devices, for our MQTT traffic.
  • We are going to organise our devices as "egg stations". 3 of them in fact. And each egg station will be identically configured to "process" the egg when it arrives. Each will consist of:
    • ESP32 development board running MicroPython. Here, we implement all the local logic required to wait for the arrival of a new egg, to "process" it, and release it once it is sure that the next station is ready to accept a new egg.
    • A HS-645MG servo to control the "gates". This will allow the eggs to be trapped at the station, then released after "processing". We will supply the PWM signal directly from the ESP32, but the servos themselves will be powered from a separate 5V power supply.
    • A light dependent resistor (photoresistor), together with a laser diode module, to act as a proximity sensor. Break in the light detected by the photoresistor signals the arrival of a new egg at the station. The photoresistor will be used in conjunction with a 100KΩ resistor to form a voltage divider circuit, for the output voltage to be measured by an ADC pin of the ESP32.
    • We want to emulate some fluctuations in processing time (so that we can have something meaningful to look at in SiteWise). And we don't want these variations to be totally random. This is why we'll introduce a DS18B20 1-Wire temperature sensor and use it to set that station's processing time. Too hot, and the station will take longer to process and release the egg. Don't forget the 4.7KΩ resistor to pull up the output from the DS18B20.

Apart from some breadboard power supply units used to power the entire circuitry, and a suspicious "factory" built from discarded cardboard that is unlikely to pass even the most lax health and safety regulations of steam-punk Victorian Britain, there's little else required to make Bruce's cremes dreams come true.

☑ Trade in your standards, here:

There are a number of uninvited civil servants with clipboards and lanyards loitering in the reception area. And Bruce can't fend them off for any longer. Or bribe them - like last time - with a week's supply of Hairy Milk (which has quite literally rolled off the unkept factory floor).

Quick - flash at them this checklist that proves to the good folks from healthy and safety and trading standards that all the counterfeiting to date has been performed to the highest regulatory standards, and that a paper trail exists in the dusty file cabinet located at the rear of the facility which is labelled "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
  7. Battle of BLEtain

Ordre du ferret:

The first part of this enterprise is all about us ferreting around the prefabricated asbestos-filled warehouse to set up our market-leading, eggtortionately priced egg stations.

  • Use MicroPython running on an ESP32 development board to turn its built-in LED on or off. print("Ha ha. What amazing fun!")
  • Make it move a horn attached to an analogue servo by supplying it with different PWM duty cycles. We use the built-in machine.PWM library to drive the servo's control signal.
  • Ah, OK. We almost forgot the tripwire, or as it is marketed in the Egg Station V2000 MK3 ULTRA sales literature, the advanced, next-gen, smart, blockchain-enabled proximity sensor. Nah, we simply read the voltage value from the voltage divider circuit consisting of the photoresistor using an ADC pin on the ESP32. This can be achieved using another built-in library - machine.ADC.
  • Then, we introduce the 1-Wire DS18B20 temperature sensor. We take temperature readings with it, using the built-in ds18x20 library.
  • All this data then gets funnelled out of our factory through our Greengrass Core device running on the Raspberry Pi. And like any good old-fashioned "edge" device, ours can be found neglected in the corner of the office, quite literally, balancing on the edge of the desk

Oh, did we forget to supply this particular backstory? Bruce has embraced the brave new world of cloud computing. After all, he's an avid reader of Linux Format, and it is why he also has a side-business p...p...p...producing black-market Penguins. But this is also the reason for him dabbling in a bit of AWS SiteWise to monitor how his factory is performing, by:

  • Creating a Model in SiteWise representing a typical egg station available on the market, and creating attribute, measurement and metric definitions for it. These definitions trickle down to the individuals assets we create based on this model.
  • Creating our Assets in SiteWise, representing the three actual egg stations we have deployed. It is important here to define individual property aliases for the specific asset's measurement definitions, as this is how we are able to map content of incoming MQTT messages to the assets in our AWS IoT (to SiteWise) Rule.
  • Creating ourselves a portal in SiteWise. We organise our illicit endeavour under a new project, drag and drop different assets around our browser, and pretend to know what it is that we're monitoring. Phew, egg-station-2 is still at 22.234 degrees Celsius, and average processing_time_ms over an hour is still well under generally accepted golden egg tolerance constant defined by the international standard of illegal chocolatier-ing measured in ωω, or Willy Wonkas*.

Study Notes: *SI unit, ωω, is not yet widely accepted in the US illegal confectionery community where ωονκα's are still used (note: 1 ωω = 0.3912371298123161231261231231 ωονκα). This discrepancy was the real reason for the failure of the Mars Bar Climate Orbiter, as the international staff binged on chocolates with varying levels of sugar content (some as high as 1256% of recommended daily allowance of a woolly mammoth, or in practical terms, one Yorkie).

Quick purr-review:

So first things first. We need to build out Bruce's machinery. You see, he doesn't like paying business rates. And his entire enterprise is probably a front for a money laundering scheme anyway. In other words, we won't actually invest in any hi-tech wares (despite what he told his "investors" down at the AGM held at the local Red Lion), but instead, manufacture himself a set of laughably primitive "egg stations" that will marshal the conveyor belt.

Each station will consist of an ESP32 development board, a proximity sensor, servo motor and a temperature sensor. The principle here is simple. Every time an egg arrives at the station, it will trigger the proximity sensor. At which point we will pretend to perform some work on it by flashing the lights, then opening the gate using a servo to release it onto the next station (only when the next station is waiting to accept a new egg).

Throughout, the ESP32 development boards are publishing its data to AWS IoT on a MQTT topic, via the local Greengrass Core running on the Raspberry Pi, which allows data to ultimately arrive in SiteWise. They also subscribe to the MQTT topic, so that they can receive updates about the other egg station's statuses (important, to know when to release the egg).

We'll go on to represent our stations as models and assets in SiteWise, and see if we can keep tabs on the factory's performance using its portal.

Officially, SiteWise is apparently still in "purr-review" status, but this won't stop us from getting our paws all over it like a Siamese cat in front of a half open tin of Tesco's Finest albacore tuna (clearly, the variant in olive oil).

The confectionery industry is big business (shown below is a legitimate UK marketplace feeding this global addiction at Easter).

It's time to crank up the production volumes, and up the sugar content to 11, before the silicone chips start to unionise and call for better pay and improved voltage regulation conditions.

What the 'egg?:

Here's what (semi) built egg stations look like... minus the servos. Most of these components were investigated in the past by the relevant authorities, and here are their damning reports:

The auditors are here. Let's go through these components, one by one.

We have used servo motors many times before in our failed robotics projects. And we remember that they require a pulse width modulation (PWM) signal with a varying duty cycle to control their angle. Sure, it's probably better to use a dedicated servo / PWM controller to drive servos, but Bruce is all about saving costs. An ESP32 can produce an acceptable PWM output (for this purpose).

MicroPython has a nice little built-in PWM library. And since we're definitely not going to supply actual power to the servo from the ESP32 development board, it's just a case of plugging in the PWM control cable from our designated ESP32 PWM pin to our HS-645MG, and instantiating our PWM pin. The 5V power will be supplied separately as servos tend to be power hungry beasts, and any drops in supply voltage resulting from substantial current draw would likely crash our delicate little ESP32s.

Note that the HS-645MG is a pretty capable mechanical sport servo, totally overkill for the purposes of opening / closing a gate to allow a single chocolate egg through.

The code snippet below will monotonously alternate the servo between two designated angles, repeatedly. Like, forever. If your chocolate bar is quite low when it comes to robotics projects, this could be the only thing you ever implement, before moving onto other more sensible hobbies, like competitive cheese rolling.

from machine import Pin, PWM, ADC
from utime import sleep_ms

PWM_PIN = const(26)
PWM_FREQ = const(50)
PWM_DUTY = (50, 100)
pwm = PWM(Pin(PWM_PIN), freq=PWM_FREQ)
while True:

Yes, this really is all this code does...

Why would we want to make some LEDs blink? For dramatic effect, of course.

While the station is processing the egg, we will make the embedded blue LED to blink. Then, when the egg is ready, for it to remain on. Once it's dispatched the egg, and is awaiting the next one to arrive, the LED can be off. This mesmerising royal ballet of LEDs can be achieved with simple code like this:

LED_PIN = const(2)
led = Pin(LED_PIN, Pin.OUT)
# Turn LED on
# Turn LED off

This is the legendary blinky-blinky, blink-blink LED action that makes all 'em IoT industrialists tip their metaphorical top hats in unadulterated excitement.

Now, let's get acquainted with the proximity sensor.

We have a voltage divider circuit, in which one resistor is a photoresistor which varies in resistance depending on the amount of light it detects. And as such, the output of this circuit (the varying voltage) can be measured using ESP32's built-in analogue to digital converter (ADC). We permanently shine a laser beam at it from a laser diode, which results in a constant high voltage at the ADC input. But when the beam is interrupted, i.e. by the presence of the egg, the voltage goes low. That's how we'll know the egg has arrived at the gate.

Here's the basic code:

PHOTO_PIN = const(33)
PHOTO_THRESH_V = const(1)
photo_adc = ADC(Pin(PHOTO_PIN))
while True:
    photoresistor_v = * 3.6 / (2 ** 12 - 1)
    if photoresistor_v < PHOTO_THRESH_V:

Cup the photoresistor to block the light, and we notice that the voltage drops and the LED turns off.

Dear respected employees,

Please handle lasers carefully, and never point them at things that you really should know better than to point at. Like your eyes. Other people's eyes. Or anything resembling eyes. No. Not even on your lunch break. Or at the work Christmas party.

Bad things will happen. You have been warned.

Yours truly,

Your responsible employer, Bruce

Finally, we'll attach a DS18B20 temperature sensor so that we can take our temperature readings. This can be achieved using the onewire and ds18bx20 built-in libraries.

import onewire, ds18x20

TEMP_PIN = const(32)
onewire_bus_pin = Pin(TEMP_PIN)
onewire_bus = ds18x20.DS18X20(onewire.OneWire(onewire_bus_pin))
temp_sensors = onewire_bus.scan()
# Devices found
# Read temperature of first device found

Clearly, beyond this, there is the actual logic that needs to be coded into the application running on the thing. We could in practise use AWS IoT Events to handle state changes, or Lambda or Step Functions to execute our event based processes. But what's not to like about a little bit of embedded programming?

MicroPython's umqtt.simple (umqtt.simple.MQTTClient()) is used to publish (via MQTTClient.publish()) and subscribe (via MQTTClient.subscribe()) to Greengrass Core (and therefore IoT Core using the Subscriptions) - after connecting (using MQTTClient.connect()) to the MQTT broker running on it. These can all be seen in the code pasted in at the end of this post.

That's it for the hardware.

Now before we go on to investigate if Bruce's Site is Wise, let's just make sure we have our three egg stations registered as things in AWS IoT. Yes, they are there. And we have their certificates and keys. Which means we're all good to go.

Also, if you were in any doubt about what these egg stations pretend to do; the first registers the egg with the big confectionery don Willy Wonka, the second arbitrarily adds 10k of calories (just don't ask how), with the last checking it for horse meat content.

Clearly, at this point, there's nothing stopping us from sending our MQTT traffic directly to the AWS IoT endpoint. It'll receive the MQTT traffic directly from the ESP32 using the client certificate, and will process them just fine.

But, as you'll know by now, we like to complicate our setup using an intermediary Greengrass Core device. It'll sit on our edge, marshalling our MQTT traffic back and forth between our devices and IoT Core using some basic Subscriptions.

Here are the Subscriptions. Notice, that we've already decided what MQTT topic we're going to use - brucesfactory/eggstation/reports. We could incorporate the device name into the topic, or even the individual sensors, but we'll keep it simple for now and use this one single topic for all our MQTT needs. Besides, we'll bury the device name and sensor readings in our MQTT JSON payload.

We're going to ensure that our MQTT payload looks something like this:

  "photo_v": 2.568791,
  "egg_counter": 1,
  "wait_time_ms": 12791,
  "processing_time": 6000,
  "timestamp": "2020-02-26T20:11:04Z",
  "station_status": "ready",
  "temperature_c": 22.5,
  "detected": 0,
  "device_name": "egg-station-1"

This is important to know, as some of this detail will later be mapped to the attributes of our assets.

Is our Site Wise? It's time to find out.

In SiteWise, we first create a Model - Egg Station Asset Model. And when we do this, we specify its measurement, transform, metric and metric definitions. These will all be inherited by the assets we produce using this model.

Notice how we've fashioned the definitions to closely mimic the data the device will send back using MQTT.

Some definitions can also be magicked up from scratch... such as the metric definitions. We've decided to create some to aggregate average data over the last hour... as it might be easier to see trends from these data sets.

We can also create a hierarchy of models, which we've decided to do. Here's Bruce's Factory Egg Station Asset Model, because we hear his long lost cousin - Charlie - is about to enter the illegal confectionery business as well.

The reason for using asset hierarchies are quite frankly better explained in the official user guide. And perhaps this is where SiteWise starts to differ from other similar AWS IoT and non-IoT offerings (many of them, we've used in the past) which help us more generally store and monitor lots of data points. Here, we're modelling the expected assets in advance, and creating hierarchical relationships between them.

We now create our actual assets: Egg Station 1, Egg Station 2, Egg Station 3. And when we do so, it's quite important that we define the unique property aliases as these are what is used later when linking AWS IoT with SiteWise. We've simply opted to use a device_name/metric as the properties, but there appears to be many ways in which to organise these, including through the use of substitution templates.

Now our egg stations are neatly organised under Bruce's Factory Egg Stations (well in advance of Charlie's IPO).

If we want any type of AWS IoT data to flow automatically into another AWS product, we're bound to require a Rule in AWS IoT. Here's one we're creating for SiteWise, and will simply pass all MQTT payloads it receives on the topic brucesfactory/eggstation/reports to SiteWise.

Except we need to also map content of our MQTT messages to our asset property aliases.

Since we are using a single topic for all our devices - brucesfactory/eggstation/reports - we're going to interrogate the device_name key in our MQTT payload to obtain the device name. This now forms our unique asset property alias for the associated asset that we want to update. In reality, it's probably best to not rely on a key in the JSON payload to identify the originating device, as this can be spoofed by any device. There are substitution templates, for example, for client ID which is recognised by AWS IoT, and therefore more securely verifiable using its client certificates.

We've repeated this for all our property aliases that we want to update.... although there are likely to be cleverer (and secure) ways to achieve the same result using more sophisticated MQTT topic naming standards and more ambitious use of substitution templates, especially if there are going to be lots of devices and attributes.

Right. We ought to be able to test this now from AWS IoT Core.

Publish an arbitrary MQTT payload..

And we see it populate the asset.

That's it.

Bruce has made it big time in the cut-throat business of the Snackioso.

All that is left for his underpaid middle management to do is to create a portal in SiteWise, to visualise the incoming data.

We create a project for Bruce's Factory.

And associate our egg station assets to the project.

And hey presto. Life is like a pack of Celebrations, a tub of Roses, or a shelf full of Dairy Milks. Or whatever unlikely analogy there is to describe a colourful assortment of gooey objects that are designed to please you only in small quantities.

There's graphs. Charts. And all sorts. And they all update in real-time (another differentiator to AWS IoT Analytics, which relies on the sporadic creation of data sets).

The pesky Panorama journalist from BBC West has departed the building (and immediately replaced with another working for Crimewatch). And the health and safety and trading standards bods have also been sent away (with bellies full of muy mal-tesers)... although we're pretty sure one was calling in the SWAT team on 999 on her way out.

Yep. The Wiltshire Police have now arrived. And there are armed response units, sniffer dogs, helicopters and everything. Time for Bruce to pack up his ICaaS (illegal chocolates as a service) operation, and live an honest life serving real confectionery at a Morrisons checkout. But only after he deals with his backstabbing cousin, Charlie.

Daily recommended allowance:

We're using the built-in MicroPython onewire and ds18x20 libraries.
...And the machine.PWM MicroPython library to drive the servo:
Voltage measurements are taken using the machine.ADC MicroPython library:
Finally, here is the official AWS IoT SiteWise User Guide. We should probably read it: