LED Clock, Part III: Alexa?

Whilst I await delivery of more WS2812 LEDs, I wanted to start investigating how I can leverage the Alexa Gadget Toolkit integration, so that when I set a timer using Alexa, my LED clock can show the countdown.

Amazon make an Echo Wall Clock which does just that.

I found an open source project called nixie-timer, which had an Alexa Integration and was written for the ESP32

After a few hours of digging around, I had a very basic idea of what the code was doing. I started by trying to replicate the flow using the OOB ESP-IDF.

After many, many, many hours, I realised that I really didn’t know what I was doing, so I went back to the nixie-timer code and added the btstack ESP32 port into my code. This meant I could at least follow the samples provided.

I began trying to run some code myself, but the Bluetooth radio wouldn’t even start. I then took one of the BTStack examples and used that as a starting point. At least they worked.

After more hours, I got the code running, with the occasional kernel panic as I figured stuff out..

Eventually, I got it responding to the Alexa queries and receiving the messages for wakeword, timeinfo and timer.

Exactly what I wanted to achieve. I’m not 100% sure I know what’s going on, but I’ll get more understanding over time.

For starters, I want to use timeinfo to set the internal clock and then I want to use the timer command to display the countdown of an alexa timer.

Now that I’ve moved back to ESP-IDF, I’m going to have to bin my existing Arduino code which powers the LED strip and look at how to make that work.

Happy with progress.

My other WS2812 strip arrived the other day, so I’ve got to look at cutting and connecting the two strips to form one long 180 LED strip. Then I get get a feel of the overall diameter and cut some MDF to house the damn thing.

LED Clock, Update!

I managed to rework the time calculation and hour hand movement!

The clock is ticking!

I removed the RTC component and just let the loop run, with simple counters to simulate the passage of second, minutes and hours.

I think the transition of the “hands” needs to be smoother, more analogue. I’ll have to investigate if FastLED can do this.

LED Clock, Part II: Tick, Tock

In Part I, I covered the basics of controlling the LEDs. This covered the hands of the clock.

The second part of my investigation covers time and how to make the clock tick. The ESP 8266 I am using for this prototyping work doesn’t include a Real Time Clock, so I was required to add an external one.

Connecting the RTC module to my Wemos D1

With the module connected, I turned to the code. I’m using Arduino for this as it’s easy to prototype and there are lots of libraries!

#include <Wire.h>      //I2C library
#include <RtcDS3231.h> //RTC library

Setup is achieved in a couple of steps. To get me started, I just set the time.

RtcDS3231<TwoWire> rtcObject(Wire);

void setup()
{
  Serial.begin(9600);

  rtcObject.Begin();

  RtcDateTime currentTime = RtcDateTime(20, 04, 22, 0, 0, 0);

  rtcObject.SetDateTime(currentTime);
}

This starts the clock. In reality, as the module I’m using is battery backed, this step should only be performed once, but I found that having a fixed “time” would make debugging the lights a little easier.

I plan to revisit this code to ensure that I grab the current time from the internet when required.

Using the time is achieved by reading it.

void loop()
{
  Serial.println("Loop()");

 //get the time from the RTC
  RtcDateTime currentTime = rtcObject.GetDateTime();

  char str[20]; //declare a string as an array of chars

  //print the time for debugging.
  sprintf(str, "%d/%d/%d %d:%d:%d", 
          currentTime.Year(),       //get year method
          currentTime.Month(),      //get month method
          currentTime.Day(),        //get day method
          currentTime.Hour(),       //get hour method
          currentTime.Minute(),     //get minute method
          currentTime.Second()      //get second method
  );

Each part of the time is available in a named method, so to get an idea of where my LEDs should be, I grabbed the hour, minute and second.

// Fetch the current time
//
hour = currentTime.Hour();
minute = currentTime.Minute() * 2;
second = currentTime.Second() * 2;

I multiply them as I’m using a strip with 120 LEDs on it.

Building on my LED control code, I make the clock tick by turning off LEDs in the right place.

fill_solid(leds, NUM_LEDS, CRGB::DarkGreen);

// Fetch the current time
//
hour = currentTime.Hour();
minute = currentTime.Minute() * 2;
second = currentTime.Second() * 2;

// Hour
leds[hour - 1] = CRGB::Black;
leds[hour] = CRGB::Black;
leds[hour + 1] = CRGB::Black; 
leds[hour + 2] = CRGB::Black;
  
// Minute
leds[minute] = CRGB::Black;
leds[minute + 1] = CRGB::Black;

// Seconds
//
leds[second] = CRGB::Black;
leds[second + 1] = CRGB::Black;

FastLED.show();

I use multiple lights to make it more visible. With it now ticking, I hastily assembled the LED strip into a circle using cardboard and sellotape. I ran a length of alarm cable from the strip to the breadboard. To see it in action, I sellotaped it to the wall!

After letting it run for quite a while, I was surprised the hour “hand” hadn’t moved. It took my wife to point out that there aren’t 60 hours on a clock face 🤣

I’m pleased with these initial results.

As for my next steps, I’m not 100% sure. I’ve got to refine the “hands” code. I also need to think about how to mount it on the wall. I suspect it won’t be self contained and I’ll probably have a control box somewhere.

I’ve ordered another strip from the excellent Pimoroni and this will, I hope, let me add another 36 LEDs to the strip, taking it up to 180, which I think will give me a nice resolution.

I’ve got to think about power too. My estimate is that I’ll need around 3.5A to power the whole affair.

Expect another blog post soon!

LED Clock, Part I: Hands

The first part of making an LED clock was actually learning how to control the LEDs in the strip.

I had experimented with the LED strip before, flashing a rainbow, before realising I had no practical use the damn thing. At the time, I had used a Neopixel library.

Upon googling the subject again, another library came recommended, called FastLED. I had a quick look at the library and decided to give it a go.

#include <Arduino.h>
#include <FastLED.h>

#define NUM_LEDS 144

CRGB leds[NUM_LEDS];

void setup()
{
  Serial.begin(9600);

  FastLED.addLeds<NEOPIXEL, D4>(leds, NUM_LEDS);

  fill_solid(leds, NUM_LEDS, CRGB::Black);
}

void loop()
{
  leds[0].red   = 255;

  leds[1].green   = 255;

  leds[2].blue   = 255;

  leds[3] = CRGB::White;

  FastLED.show();
}
Four LEDs lit with different colours

Flashing an LED was just a case of turning it “black” and blue.

#include <Arduino.h>
#include <FastLED.h>

#define NUM_LEDS 60
CRGB leds[NUM_LEDS];

void setup() 
{ 
  Serial.begin(9600);
  FastLED.addLeds<NEOPIXEL, D2>(leds, NUM_LEDS); 
}

void loop() 
{
  Serial.write("On");

  leds[1] = CRGB::White; 
  FastLED.show(); 
  delay(30);
	
  Serial.write("Off");

  leds[1] = CRGB::Black; 
  FastLED.show(); 
  delay(30);
}
Flashing between white and “black”

I experimented a little more and ended up with a moving yellow light and a pretty static red slash of colour. This was sort of how I imagined the clocking running.

Power consumption was also on my mind. I had read that the each WS2812 on the strip would consume around 80mA. With my intention to power 180 of these, the power requirement was around 12A. This seemed very excessive, especially given the puny wires that were soldered to the strip. If somebody had tried to light them with that power consumption, the wire would have evaporated.

With my initial experimentations, a year before, I was sure I had run a LED rainbow lighting program through it and I new my 3A supply did the job and nothing went on fire.

I hooked it all up and lit all 144 LEDs.

It was only consuming 2.7A, including 200mA required to run the ESP8266 that was controlling it. I knew I’d need another 0.7A to power the intended 180 LEDs. This put the consumption at a little under 20mA for each WS2812.

With the LEDs under control, my next area of investigation was Real Time Clocks. I’ll do a post about that, once I’ve got something to report!

Lockdown LED Clock

A year or two ago, I picked up a WS2812B LED strip, but, for the life of me, could never think of anything useful to do with it.

Recently, however, I came across these LED powered clocks.

This feels like a project that will combine a few things:

  • ESP MCU
  • Real Time Clock
  • WS2812B strip
  • Maybe some Alexa integration?

Since I’m working from home for the duration, due to COVID-19, I get to recoup my usual commute time and put it towards something.

My starting point will be hooking up the strip to an ESP32 and trying to light one of the LEDs. I plan on a series of posts as I work towards my own clock!

Part I – https://tomasmcguinness.com/2020/04/14/led-clock-part-i-the-leds/

Part II – https://tomasmcguinness.com/2020/04/25/led-clock-part-ii-tick-tock/

Do we have any hot water?

A common occurrence in our house is bath time.

Another common occurrence is not having enough water for afore mentioned bath.

Our hot water is provided by a system boiler/unvented cylinder arrangement and I use a Nest to control the hot water (more on that later). The current schedule has it running the boiler for thirty minutes each day.

What is very annoying is that on some bath days we have ample hot water and on others, we don’t. We end up boiling the kettle to make up the difference. I don’t like the idea of just turning on the hot water as we might just be heating water that is already hot enough.

How much hot water do we have?

The first thing to figure out is how much how water we actually have. As I’ve mentioned, one some days we have ample and on other days we run out. Why does this happen?

Here are a few of the main factors that spring to mind:

  • The duration of the showers in the morning.
  • The ambient temperature in the loft.
  • How much washing up we’ve done.

The image above shows the basic operation of an unvented cylinder. Cold water enters the tank at the bottom and hot water exits at the top. The coil inside the tank is connected to the boiler and is responsible for actually heating the water in the tank. The whole thing works off the principal that the hot water will sit on top of the cold water and be pushed out the top.

My plan, therefore, was to attach temperature probes to the cold water entry and hot water exit and see what I could measure.

I was also interested in trying to measure the effect of the loft temperature on heat loss.

The Sensor

With my requirement of three sensors, I set about building a circuit that included an ESP-8266 and three DS18B20 temperature probes.

The DS18B20 uses something called the OneWire protocol, which means you can connect multiple sensors in parallel and use a single GPIO to read all the values. I found an excellent tutorial on the subject here – https://lastminuteengineers.com/multiple-ds18b20-arduino-tutorial/

With the long DS18B20 probes attached
The three temperature probes connected to the D1

For power, I wanted to use an off the shelf power supply. As these are mostly 5v, I added an LV1117V33 LDO. This little device accepts up to 7v input and outputs 3.3v, which was perfect to power the D1 and the sensors. To this, I connected a barrel input.

Powering the device with a 5v power supply

Software

I had originally planning on writing my own software to read the values from the sensors and send via MQTT to my HA instance. I actually did write my own software and even got the auto-discovery working, but as I wanted a web UI running on the device, so I could change easily change WiFi and MQTT settings, going down the custom road made little sense.

I was vagly aware that the excellent Tasmota Firmware (which I use in lots of smart sockets) did have some form of sensor support, so I did some reading. It turns out that not only did it support the DS18B20 sensor, it supported multiple ones 🙂

I flashed it onto the D1 mini and, after setup, navigated to the Configuration page.

You can select Module type as Generic (18) to gain access to the various GPIO pins on the device. I had connected the data wire of my sensors to D4, which is GPIO2. I choose teh DS18x20 option.

Setting up GPIO2 to handle the temp sensors

Once I hit save, the device rebooted and, lo and behold, the temperature started flowing into the UI!

Housing

Knowing how dusty my attic can be, I wanted to house the electronics in something, just to keep it clean and tidy. I had some Hammond enclosures (https://www.hammfg.com/electronics/small-case) and one of them seemed perfect.

I drilled four holes. One for each of the temperature probes and one for the power connector. The probes are held by three IP68 glands. Not necessary at all, but I just had them and thought they’d suit.

All the holes drilled and the sensor glands added
Circuit board installed
Lid on.

Once I had it all assembled, I plugged it in. It was at this point I wished I had some sort of indicator light to tell me it was powered or connected to the internet. I had to wait a minute, but eventually the Tasmota appeared on my list of connected clients.

Installation

I have a pretty standard unvented cylinder. There are two pipes entering at the bottom, the cold water inlet and the hot water return to the boiler. The hot water outlet is at the top.

My hot water tank in all its glory!
I stuffed one of the probes under the lagging at the top
The cold water inlet at the back – It isn’t even fully lagged!
I stuff another probe up against the cold water.

The third probe I just left hanging in the air, supported by a piece of furniture. My loft really is full of junk!

The data

The reading from the probes

From the three probes, I could have a guess as to which probe was were!

The 15.8 was the ambient temperature in the loft, with the 19 and 48 degree measures pointing to the inline and outlets.

Measures taken first thing in the morning

My hot water turns on for 30 minutes each morning (30 mins because the Nest Thermostat won’t let me do anything shorter). I looked at the temperatures when I got up around 7am and I could see the top temp was at almost 60 degrees.

Next Steps

I’m going to let this setup run for a few weeks and note the days we run low/out of hot water.

Combined with better control of my hot water (I’m thinking of replacing my Nest’s control), I think there is an opportunity to reduce the time my hot water needs to actually be turned on.

Other things might be possible, such as extra hot water when we have guests over (using their connection to the house WiFi as an indicator of presence). Or ensuring these is hot water for washing the dishes at 6pm each night.

I’ll post an update, once I’ve got some findings!

Update 24th Feb

With the sensor installed for over a week, I pulled a graph from Home Assistant.

A week’s worth of readings

The green line, which reaches the highest values is the outlet temperature. You can see the rather pronounced peaks and troughs. The orange line represents the inlet temp and that does spike a little, each morning, when the heating is turned on. The red line is the ambient temp of the loft. It does vary by a few degrees.

From the graph, it’s very obvious when we’re very low on hot water!

I also find the temperature loss over the course of the day to be interesting. This is obviously a function of the ambient temperature in the loft, but also, I suppose, of the temperature of the incoming water.

I’m in the process of upgrading my Home Assistant instance and I hope to be able to retain more data than I can do right now. I’d like to be able to compare summer months to winter months, so I need a few months of stored data to perform that comparison.

More to come!

TS MK II – Mesh Network Pt.2

As part of my Temperature Sensor upgrade, I’ve started looking into Mesh Networking support.

Documenting my progress

Rather than try and put a post together at the end, I’m going to try and document my progress as I go, with additions to this post each time I do something significant.

The beginning

I recommend you read the first post before picking up here.

31th July

I carried on through the developer study guy and implemented the basic Light. The messaging flow is now making sense to me. I knew the Microbit’s 16KB of RAM wasn’t going to be enough for any real project, so I decided to bite the bulled and pick up a Adafruit nRF52832 device.

Ordered from www.coolcomponents.co.uk, they arrived pretty quickly. I plugged it in, downloaded the Bluefruit app from the app store and was able to discover and connect to the device pretty quickly. So far, so good.

Unfortunately, I couldn’t flash it my Zephyr project. More digging around, using the Nordic Tools and I discovered that the West tool couldn’t detect the device. Strange, as I could flash it with simple Arduino sketches. I trawled the documentation. Tried changing drivers. Updated the bootloader. Nothing had any effect.

During the umpteenth reading of the Zephyr docs, I finally realised why:

Flashing Zephyr onto the nrf52_adafruit_feather board requires an external J-Link programmer. The programmer is attached to the X1 SWD header.

https://docs.zephyrproject.org/latest/boards/arm/nrf52_adafruit_feather/doc/index.html

I have emphasized external in the quote above. I totally missed that key piece of information. More googling and I learn that Segger J-Link is a special protocol and that a small unit is required to interface your computer with the board! Everything fell into the place. The different drivers and the talk of the SWD header.

Unfortunately, my Adafruit boards don’t have a SWD header. Fortunately, the board has space and solder pads for one to be added.

The SWD header goes here

Adafruit sell the headers, but nobody in the UK had them available. I searched around and found something on RS that looked right.

I wasn’t prepared for the tininess of the header

I found a J-LINK device on The PiHut which I ordered, along with a short cable. I’ll wait for that to arrive before I attempt to solder this header onto the board. I’m going to need some steady hands!!

3rd August

J-Link Device arrived and connected up. Managed to solder on the header without any issue.

Added the RS 10 pin SWD header to my Adafruit nRF52

I think hooked up my newly purchased J-LINK device. Side node here – I ordered a serial cable with this as PiHut said it was recommended. One came in the box, so the extra one I ordered was redundant! I’ll be writing to them about that.

Hooked up (I should point out that this shows the correct cable orientation – see below)

Running the nordic command shows it has found the J-LINK connector!

Sadly, nothing is easy…

Big cryptic error trying to flash the device

My attempt to flash the hello_world sample failed. Ah man – with some help from this https://embeddedcomputing.weebly.com/segger-j-link-with-adafruit-feather-nrf52.html I realised I had the cable connected the wrong way around. I could find no information on the orientation of the header or cable, but I reversed it based on that pic and boom…..

SUCCESS!

Zephyr hello_world sample successfully written to device

It appeared that I had successfully flashed the device with the sample code.

Terminal output shows hello_world is working

Bloomin’ heck. It did actually work!

With the flash process *finally* working, I create a new “light” project, using what I’d learned from the BBC Microbit. I was then able to reuse the BBC Microbit switch.

I’d consider that a success! I think I’ve enough of a basic grasp of BLE Mesh networking to park this part of the project and move on!

TS Mk II – Mesh Network Pt.1

As part of my Temperature Sensor upgrade, I’ve started looking into Mesh Networking support.

I was aware that the Expressif ESP32 supports the new Bluetooth LE Mesh protocol, and as Bluetooth Low Energy would help stretch battery life, it seemed like the natural place to start my investigations.

I was initially going to try the WiFi mesh, but it didn’t really seem to suit devices like temperature sensor as they are actually asleep most of the time. If nodes in the mesh keep turning on and off, the other devices in the mesh would be constantly reorganizing themselves to plug the gaps. I do want to learn about ESP’s WiFi mesh, but for now, I’ll focus on Bluetooth

Documenting my progress

Rather than try and put a post together at the end, I’m going to try and document my progress as I go, with additions to this post each time I do something significant.

Getting started

I’ve already got the ESP-IDF environment setup and have two different dev boards. I’m going to try and approach this in stages

  • Copy one of the sample projects and get it running
  • Add another node
  • Send data from one node to another
  • Add MQTT and WiFi to get data out of the mesh

9th July 2019

I pulled down the ESP-IDF code from their mesh branch and spun up on the samples. After faffing around with the menuconfig settings, I got the Node example compiled and deployed onto the device. It also appeared appeared in the Nordic iOS Mesh App.

I found a good post on the provisioning process, https://www.novelbits.io/bluetooth-mesh-tutorial-part-3/ and this helped me make sense of what I was seeing.

Once I tapped on the node, I was able to tap “Identify”, which pulled back more information. I think this is what novelbits called “Invitation”. I then tapped “Provision” and after a few seconds, and a lot of logging from the device, I had the first Node in my mesh!

11th July

Now that I had my first mesh node, I quickly realised why the Expressif code was only at version 0.6 – none of the provisioning data was being saved. This meant that each time I flashed the device, I had to provision it again. This became annoying after the fifth time, so I started digging into the actual provisioning process, to see if I could put in something temporary.

I was digging around on google and I came across the Zephyr RTOS. In their examples, they had a simple 2 node mesh demo. The readme page states that no provisioning is required, and whilst it’s insecure, it’s sufficient for the demo. In their code, I could see a few lines of code where they manually provision the device with their own network and device keys.

static const u8_t net_key[16] = {
	0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
	0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
};
static const u8_t dev_key[16] = {
	0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
	0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
};
static const u8_t app_key[16] = {
	0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
	0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
};

err = bt_mesh_provision(net_key, net_idx, flags, iv_index, addr, dev_key);

This seemed ideal for my tinkering. I also found reference to the Zephyr code in Expressif’s news release about their BLE Mesh, where they state they are basing their implementation on top of the Zephyr . This meant I could probably find simple code in the esp-idf repo.

Running this code on the device resulted in it saying that provisioning was complete.

19th July

After more digging around the ESP-IDF examples, I came across some testing code, which appeared to provision using the esp code.

bt_mesh_device_auto_enter_network()

Try as I might, I couldn’t get that to work. Just kept reporting an error of -22.

UPDATE 13th August: During some experimenting with how to bridge the mesh network with MQTT, I managed to get this code working eventually, meaning:

static const u16_t net_idx;
static const u16_t app_idx;
static const u32_t iv_index;

struct bt_mesh_device_network_info info = {
        .net_key = { 
                    0x01,
                    0x23,
                    0x45,
                    0x67,
                    0x89,
                    0xab,
                    0xcd,
                    0xef,
                    0x01,
                    0x23,
                    0x45,
                    0x67,
                    0x89,
                    0xab,
                    0xcd,
                    0xef,
                    },
        .net_idx = net_idx,
        .flags = flags,
        .iv_index = iv_index,
        .unicast_addr = 0x0002,
        .dev_key = {
                    0x01,
                    0x23,
                    0x45,
                    0x67,
                    0x89,
                    0xab,
                    0xcd,
                    0xef,
                    0x01,
                    0x23,
                    0x45,
                    0x67,
                    0x89,
                    0xab,
                    0xcd,
                    0xef,
        },
        .app_key = {
		0x01,
		0x23,
		0x45,
		0x67,
		0x89,
		0xab,
		0xcd,
		0xef,
		0x01,
		0x23,
		0x45,
		0x67,
		0x89,
		0xab,
		0xcd,
		0xef,
},
        .app_idx = app_idx,
        .group_addr = 0xc000
    };

    err = bt_mesh_device_auto_enter_network(&info);

20th July

After more attempts to provision the device directly, I’ve decided to kinda give up. As I mentioned, the Zephyr code is easier for me to understand at this stage, so I’m going to try and get a build of the Zephyr samples running on my ESP32 boards.

23rd July

After hours of playing around trying to get the Zephyr SDK compiling against the ESP32 toolchain, I decided to stop. I found an excellent resource at over on the Bluetooth SIG website, called “An Introduction to Bluetooth Mesh Networking“. The samples in their course use the Zephyr SDK and the BBC Microbit. I had a glance though it and most of the main concepts are covered, so I think I’ll order some BBC Microbits and run through it.

I also came across an interest post at https://hutscape.com/, which is worth checking out. The author, Sayanee, uses an Adafruit board to build a UV sensor. Pretty cool. At £26 (and no Friend Node support in the Nordic SDK), I decided against buying any for the time being.

24th July

I got a BBC Microbit and tried the Zephyr mesh_demo code. After more mucking around, I managed to flash it with their code.

Building the mesh_demo firmware
The output from the microbit shows it working

As suggested by the Bluetooth study guide, I turned on the logging and then

Enable the logging and I use up too much RAM

The damn firmware, with logging, was too big for the BBC Microbit’s 16KB of ram. Bloody hell. Nothing is every easy. Some googling revealed that the small amount of SRAM makes it almost impossible to run the mesh. The Apollo Computer ran on 4KB of RAM 🙂

Hardware development is tough! That said, these microbits are perfect for me to dabble in the fundamentals of Bluetooth Mesh and to get to grips with the models. Hopefully there is enough space for me to try my own code. Perhaps it’s possible to compress the Zephyr RTOS runtime down a little??

25th July

Been reading about how to figure out the size of the runtime. You just run the command ninja rom_report

The mesh_demo code takes up just over 3% of the total size
The bluetooth code takes up 66%

I don’t know what those numbers actually mean. I had assumed bytes, but that would mean the bluetooth library, if measured in bytes, was around 50KB and I know that’s not right.

28th July

I experimented with the Zephyr mesh_demo sample, but couldn’t make it work. Kept getting error codes when trying to send messages. I tried to tweak it here and there, but I was just strumbling around in the dark. I returned, instead, to the Bluetooth developer guide and gave that go. The guide starts at the Switch module.

The sample code wasn’t up-to-date with the latest Zephyr code, so I had to tweak it somewhat, but I got it to compile and, amazingly, it worked.

One Microbit is the light, the other the switch
Turning the light on and off over BLE Mesh!

You can continue following my adventures here