Gerrit Niezen

Maker of open-source software and hardware.

You already know that air pollution is a big problem, but you're not sure what you can do about it personally? Instead of waiting on the government or other people to solve the issue, here are 4 practical things you can do to improve air quality:

Stop burning stuff

Wood-burning stoves are one of the leading causes of air pollution in countries like the UK. Even a candle in your living room emits particulates. While we may have romantic or cozy feelings towards burning stuff, it's not great for our lungs.

Get on your bike

Even electric cars emit particulates when braking, so the best way to get yourself from A to B is on a bicycle or by walking. For longer journeys, public transport is the way to go.

Grow plants

Back in the 1980s NASA did this study to show that plants are great at purifying the air. Though later studies didn't quite replicate their results, having some beautiful green plants in your house is never a bad thing.

Switch to an induction stove

Gas stoves generate a lot of particulates during cooking, and you can cut down on this by using an induction stove instead. Is the convenience of a gas hob really worth the risk to your family's health? You may just find that a modern induction stove is just as convenient as the gas version.

With the current global chip shortage it can be challenging to find the right chip for your project that's actually in stock. I want to share some of my own challenges and what the options are. First up: What LiPo battery charger chips can be used with solar panels?

BQ24074

I first came across Texas Instrument's BQ24074 while looking at Adafruit's Universal USB / DC / Solar LiPo charger, which replaced their earlier MCP73781-based charger. It's relatively inexpensive ($0.81) and has an input voltage of up to 10V. Unfortunately this chip was out of stock when I ordered my board for SMT assembly, so I had to consider alternatives.

LT3652

Analog Device's LT3652 is used in Sparkfun's Sunny Buddy (MPPT Solar Charger), but it's a lot more expensive (around $5) than other chips and was also out of stock at the time of ordering.

CN3065 / CN3063

Consonance Electronic's CN3065 is used in Seeed Studio's LiPo Rider boards, as well as many low-cost solar battery charger boards on eBay. It's even cheaper than the BQ24074 at around $0.50, and it was available in its SOP8 package version CN3063 at JLCPCB when I placed my order. While it has been working great so far, it only has an input voltage of 6V, which could cause issues if you get high peak voltages on your solar panel over an extended period of time.

What are your favourite tools when building hardware?

Multimeter

If you're working with electronics, you need to be able to measure voltages, current, resistance and continuity. I mostly use a $10 multimeter to check if voltages are at the right levels and if there's continuity between various parts of the circuit. You'll notice there's no oscilloscope on this list. If you're only working with digital electronics, an oscilloscope feels like an unnecessary luxury. Most of what you need to figure out can be done with a multimeter and a logic analyser.

Logic analyser

My $10 logic analyser from eBay only measures up to 24MHz, but I've been able to successfully decode USB traffic that typically would be done with a USB analyser costing 50 times as much. The open-source Sigrok PulseView software supports a wide range of protocols for decoding, and is surprisingly easy to use.

Digital calipers

If you have a 3D printer, you're going to find digital calipers useful. It makes it so much easier to measure the dimensions of enclosures, components and circuit boards. I bought a super-cheap plastic digital caliper for $7, and so far it's been working just fine. I find myself using it so often that I could easily spend a little bit more on one that allows for finer adjustments.

USB-to-TTL converter

If there's any kind of UART serial communication between your microcontroller and peripherals, a $5 USB-to-TTL converter is a very useful addition to your toolbox.

Software-defined radio

This may sound like an unusual addition to this list, but being able to use a $10 DVB-T USB stick as a software-defined radio is priceless if you're working on a wireless project. I've used mine to measure the length of pulses while building a circuit to communicate with a remote control socket, and to check that what I'm building is actually sending data over the air.

#electronics #OpenHardware

Moisture sensor

To know when I need to water my seedlings in the propagator, I got an analogue capacitive soil moisture sensor for £3.67 (including P&P).

The pinout is a simple three-wire interface, with Vcc, ground and the analogue output pin. To read the values, I just needed to do the following in Espruino:

const moistureSensorPin = A5;
const airMoisture = 955;
const waterMoisture = 670;

pinMode(moistureSensorPin, 'analog');

const moisture = Math.round(analogRead(moistureSensorPin) * 1000);
const moisturePercent = Math.round(map(moisture, airMoisture, waterMoisture, 0, 100));
console.log(`Moisture is ${moisture} ~ ${moisturePercent} %`);

if (moisturePercent < 16) {
  console.log('Needs more water');
  // TODO: alarm notification
}

To get airMoisture and waterMoisture, I took readings from the sensor when it was dry and placed in a glass of water respectively. The map() function I got from the Arduino libraries:

function map(x, in_min, in_max, out_min, out_max) {
  // from https://www.arduino.cc/reference/en/language/functions/math/map/
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

I place the sensor directly under the rockwool cubes of the seedlings to measure the moisture content.

Water level sensor

To detect the height of the water level sensor, I'm using a VL53L0X LIDAR sensor, that uses a laser and time-of-flight measurements to accurately measure distances between 50mm and 1200mm. It's pretty amazing that they can fit a laser and a detector into a package that's barely larger than a grain of rice.

The sensor uses an I2C interface, so I connected the pins as follows:

  • SDA pin to Espruino B3
  • SCL pin to Espruino B10
  • GND pin to ground
  • VIN pin to Espruino 3.3V
  • X pin to Espruino 3.3V (maybe not necessary)

To set it up in Espruino, you just do:

  I2C2.setup({ sda: B3, scl: B10 } );
  laser = require("VL53L0X").connect(I2C2);

To then perform a measurement, you do:

// measure water level
const distance = laser.performSingleMeasurement().distance;
if (distance > 20) {
  console.log(distance, 'mm');
  // TODO: minimum water level notification
}

I’m publishing this as part of 100 Days To Offload. You can join in yourself by visiting https://100daystooffload.com.

#100DaysToOffload #day67 #hydroponics

For my hydroponics setup there are a bunch of reasons why I would want to be notified of an issue, e.g.:

  • Temperature of range
  • Lights on/off outside of schedule
  • Water overflow
  • Humidity out of range
  • Water level too low

Since my setup is based around using Bluetooth LE for wireless communication, that means I need to think about how to get notified about these issues on my mobile device.

It used to super simple to get mobile notifications in Android from Bluetooth using Eddystone-URLs, but Google disabled this in 2018 due to abuse by marketers. Eddystone and iBeacons are now only supported in native apps.

It is possible to send web push notifications from a PWA, but this requires service worker support, which is not supported by Web Bluetooth yet.

This leaves having a web server somewhere within range of the Bluetooth device, that can subscribe to Bluetooth notifications an send send these out as web push notifications to your mobile device.

Edit: There is also another option: The Physical Web Association now provides an unbranded native app that can be used to interact with Eddystone-URL beacons. Maybe this app can then launch the PWA?


I’m publishing this as part of 100 Days To Offload. You can join in yourself by visiting https://100daystooffload.com.

#100DaysToOffload #day66 #hydroponics

For my hydroponics setup, I want to be able to turn on and off both the LED grow lights and the water pump using a microcontroller. This is typically done using relays, and is the implementation I described in yesterday's blog post.

I've been thinking it over more and realising that having a solution that can be implemented by anybody shouldn't rely on dealing with AC mains voltages and wiring. Smart plugs using Bluetooth or WiFi having been coming down in price a lot, to the extent that they're a viable alternative to relays, especially if you take the cost of AC sockets and enclosures into account. If you don't want to have exposed wiring, you may want to consider putting your electronics inside a plug case.

Smart plug options

Bluetooth LE smart plugs are used by HomeKit and Philips Hue, but they're still a bit expensive at around £30 per plug. They also don't make use of the standardised Bluetooth profiles and services, but implemented their own proprietary BLE services.

WiFi smart plugs are around £10 each, and you can buy a WiFi power Strip with 3 outlets for £30. Unfortunately these smart plugs are getting more locked down, where you may be forced to use the manufacturer's app and proprietary API to get access to the plugs.

Thanks to Espruino's excellent documentation, I found another option: remote control sockets at around £5 each. They operate in the 433MHz range, which means you use a dirt cheap 433MHz transmitter to talk to them.

I really like this last option, as they use a simple wireless protocol that's easy to implement, and they're almost cheaper than using relays.


I’m publishing this as part of 100 Days To Offload. You can join in yourself by visiting https://100daystooffload.com.

#100DaysToOffload #day65 #hydroponics

For my ebb-and-flood (also called flood-and-drain, or ebb-and-flow) hydroponics system, I need to pump water over the flood table at regular intervals. The time between flooding depends on various things, of which the growing medium is the deciding factor:

  • Expanded clay pebbles: 4 to 8 times a day (every 2 to 4 hours)
  • Coconut coir: 3 to 5 times a day (every 3 to 5 hours)
  • Rockwool: 1 to 5 times a day (once a day to every 3 hours)

I'm going to put rockwool starter cubes in expanded clay pebbles, so every 3 hours sounds like a good idea. I then also need to figure out how long to flood the table for, which depends on how quickly the pump floods the table. Let's say it's around 30 seconds, which then leads to the following Espruino script for my Pixl.js:

const floodIntervalMinutes = 180;
const floodDurationSeconds = 30;

const pumpPin = B15;
const waterSensorPin = B3;

setInterval(() => {
  if (!digitalRead(waterSensorPin)) {
    console.log('Water detected!');
    digitalWrite(pumpPin, 0);
  }
}, 1000);

setInterval(() => {
  // TODO: check if daylight
  // TODO: max delay between floodings

  digitalWrite(pumpPin, 1);

  setTimeout(() => {
    digitalWrite(pumpPin, 0);
  }, floodDurationSeconds * 1000);

}, floodIntervalMinutes * 60 * 1000);

function onInit() {
  pinMode(waterSensorPin, 'input');
  pinMode(pumpPin, 'output');

  E.setTimeZone(1);
  console.log('Current time:', (new Date()).toString());
  digitalWrite(pumpPin, 0); // make sure pump is off
}

Note that I also added a water sensor for switching off the pump in case there's an overflow.

What I still need to do is to add a light sensor to check if there's daylight, and then only flood during daylight hours. I then also need add a maximum delay between floodings, so that the plants don't go for more than 12 hours without water. Thanks to ChilliChump for these ideas.


I’m publishing this as part of 100 Days To Offload. You can join in yourself by visiting https://100daystooffload.com.

#100DaysToOffload #day64 #hydroponics

This morning I discovered Trefle, an API for plants, through the r/hydro Reddit. What is exciting is that it does seem to cover a number of the variables I'm looking to include in my growing spreadsheet:

  • days to harvest
  • pH range
  • light range
  • temperature range

There are also other interesting fields, e.g.:

  • humidity
  • spread
  • average height

Trefle gets its information from a bunch of sources, including USDA, Kew Royal Botanical Gardens, Wikimedia and PlantNet.

While Trefle itself isn't open-source, it should always be free for open-source projects. Another alternative to consider, that is open-source, is OpenFarm.


I’m publishing this as part of 100 Days To Offload. You can join in yourself by visiting https://100daystooffload.com.

#100DaysToOffload #day63 #hydroponics

For my hydroponics project, I would like to measure the ambient temperature. I've done this in the past as a WiFi temperature sensor, but this time round I wanted to use my Pixl.js board with Bluetooth LE connectivity.

Here is the code to read data from a DS18B20 temperature sensor, display a temperature graph on the Pixl.js screen, and also make it available via Bluetooth LE as an Environmental Sensing Service.

const PIN_SENSOR = A1;  // Pin temperature sensor is connected to

let ow, sensor, history;
let avrSum = 0, avrNum = 0;
let lastTemp = 0;

// Draw the temperature and graph to the screem
function draw() {
  g.clear();
  g.setFontVector(30);
  g.setFontAlign(0,-1);
  g.drawString(lastTemp.toFixed(1), 64,5);
  g.setFontBitmap();
  g.drawString("Temperature", 64, 0);
  require("graph").drawLine(g, history, {
    axes : true,
    gridy : 5,
    x:0, y:37,
    width:128,
    height:27
  });
  g.flip();
}

// Called when we get a temperature reading
function onTemp(temp) {
  if (temp === null) return; // bad reading
  avrSum += temp;
  avrNum++;
  lastTemp = temp;

  // send on BLE
  const th = Math.round(lastTemp * 100);
  NRF.updateServices({
    0x181A : { // environmental_sensing
      0x2A6E : { // temperature
        value : [th&255,th>>8],
        readable: true,
        notify: true
      }
    }
  });

  draw();
}

// take temp reading and update graph
var readingInterval = setInterval(function() {
  if (sensor) sensor.getTemp(onTemp);
}, 10000);

// save average to history
var histInterval = setInterval(function() {
  history.set(new Float32Array(history.buffer,4));
  history[history.length-1] = avrSum / avrNum;
  avrSum = 0;
  avrNum = 0;
}, 60000); // 1 minute

// At startup, set up OneWire
function onInit() {
  try {
    ow = new OneWire(PIN_SENSOR);
    sensor = require("DS18B20").connect(ow);
    history = new Float32Array(128);
    avrSum=0;
    avrNum=0;

    NRF.setServices({
      0x181A: { // environmental_sensing
        0x2A6E: { // temperature
          notify: true,
          readable: true,
          value : [0x00, 0x00, 0x7F, 0xFF, 0xFF],
        }
      }
    }, { advertise: [ '181A' ] });
  } catch (e) {
    console.log('Error:', e);
  }

This code is based on the lovely Pixl.js Freezer Alarm example.

I then wanted to be able to connect to the sensor via Web Bluetooth in the browser, which led to this web app:

document.addEventListener('DOMContentLoaded', event => {
  const button = document.getElementById('connectButton')
  let device

  button.addEventListener('click', async (e) => {
    try {
      if (button.innerHTML === 'Disconnect') {
        device.gatt.disconnect()
        button.innerHTML = 'Connect'
        return
      }
      document.getElementById('p1').innerHTML = 'Connecting'
      console.log('Requesting Bluetooth Device...')
      device = await navigator.bluetooth.requestDevice({
        filters: [{
          namePrefix: 'Pixl.js'
        }],
        optionalServices: ['environmental_sensing']
      })

      device.addEventListener('gattserverdisconnected', onDisconnected)

      console.log('Connecting to GATT Server...')
      const server = await device.gatt.connect()
      button.innerHTML = 'Disconnect'

      console.log('Getting Environmental Sensing Service...')
      const service = await server.getPrimaryService('environmental_sensing')

      console.log('Getting Temperature Characteristic...')
      const characteristic = await service.getCharacteristic('temperature')

      console.log('Reading temperature...')
      const value = await characteristic.readValue()
      const temp = value.getUint16(0, true) / 100

      console.log('Temperature is ' + temp)
      document.getElementById('p1').innerHTML = temp

      await characteristic.startNotifications()

      console.log('Notifications started')
      characteristic.addEventListener('characteristicvaluechanged', handleNotifications)
    } catch (error) {
      console.log('Argh! ' + error)
      document.getElementById('p1').innerHTML = error
      button.innerHTML = 'Connect'
    }
  })

  function handleNotifications (event) {
    const value = event.target.value
    const temp = value.getUint16(0, true) / 100

    console.log('Temperature is now ' + temp)
    document.getElementById('p1').innerHTML = temp
  }

  function onDisconnected () {
    console.log('Disconnected.')
    button.innerHTML = 'Connect'
    document.getElementById('p1').innerHTML = 'Disconnected'
  }
})

The index.html file looks like this:

<html>
  <head>
    <title>Hydroloop</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <script src="main.js"></script>
    <link rel="stylesheet" type="text/css" href="main.css">
  </head>
  <body>
    <button id="connectButton" class="buttons">Connect</button>
    <p id="p1" class="text"></p>
  </body>
</html>

One Web Bluetooth discrepancy that I discovered between desktop Chrome and Chrome on Android, is that desktop Chrome will still read a value from a service, even if the characteristic is not set to be readable. Chrome on Android, on the other hand, will throw an error. That's why you see both readable: true and notify: true in the code above.

This works great! Temperature readings in the browser are automatically updated, and it even shows you when you get disconnected from the sensor.


I’m publishing this as part of 100 Days To Offload. You can join in yourself by visiting https://100daystooffload.com.

#100DaysToOffload #day62 #hydroponics

I've been working on building a DIY hydroponics system for the past two weeks, and have inevitably run into a number of issues already.

Spray painting

I bought two clear containers that I spray painted to prevent light from entering the container. Light could cause algae growth in the nutrient inside the containers. The first problem that cropped up was that spray painting can be very time consuming. The actual painting part is relatively quick, but you then have to wait around 20 to 60 minutes between coats, and at least 24 hours for the paint to fully dry. If you don't have a covered area to do the painting, rain delays progress even further.

As I didn't use a primer, the paint start cracking off as soon as the plastic started flexing. Flexing can happen when filling the container with water, or when drilling holes for piping.

As such, I'd recommend not spray painting plastic containers if you can avoid it. I ended up going to IKEA and buying two opaque TROFAST storage boxes instead.

3D-printed parts

As the fittings for ebb-and-flood systems are pretty expensive in the UK (£13 vs $6 in the US), I thought I'd 3D print them. The full print took about 13 hours, which is still faster than next-day delivery. They worked great until I switched to the new containers, when one of the fittings broke off completely.

I printed them in ABS, which is maybe not the greatest option for functional parts. I've now ordered some PETG filament from Prusa which should result in sturdier parts.

Seedlings

The kale seeds I planted in the propagator only took a day or two to start sprouting. They started stretching very quickly due to lack of natural light, even though the propagator was placed on a windowsill. My Spider-Farmer SF1000 grow light arrived yesterday, so this morning I planted some new seeds and placed the propagator under the grow light immediately.

It has not been smooth sailing so far, but if you don't fail, you don't learn.


I’m publishing this as part of 100 Days To Offload. You can join in yourself by visiting https://100daystooffload.com.

#100DaysToOffload #day61 #hydroponics

Enter your email to subscribe to updates.