Alistair MacDonald
Published © CC BY-NC-SA

Tipper Tracker

A device to monitor to track bin usage and help predict collection requirements.

IntermediateFull instructions provided3 hours388

Things used in this project

Hardware components

AVR IoT Mini Cellular Board
Microchip AVR IoT Mini Cellular Board
Tilt Switch, SPST
Tilt Switch, SPST
Rechargeable Battery, 3.7 V
Rechargeable Battery, 3.7 V

Software apps and online services

Arduino IDE
Arduino IDE
DX Core
Arduino support for the AVR DA, DB-series

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)
3D Printer (generic)
3D Printer (generic)
Laser cutter (generic)
Laser cutter (generic)


Read more

Custom parts and enclosures

Internal base holder

A frame to hold the device and battery in place. Printed from PET-G or PLA.

External cover

A cover to hold the tracker to the bin and protect it. Printed from PET-G or TPU.

Cover plate

A plate to close the internal base 3D print in the external cover.


Tipper Tracker Wiring Diagram


Tipper Tracker Firmware


   Tipper Tracker firmware
   Alistair MacDonald 2024

#include <Arduino.h>
#include <http_client.h>
#include <led_ctrl.h>
#include <log.h>
#include <low_power.h>
#include <lte.h>

#include <mcp9808.h>
#include <veml3328.h>

#define DOMAIN ""

// Consifuration

// Pin for the test button - D11
#define SW0 PIN_PD2
// Pin for the tip up switch - D10
#define SW1 PIN_PB5
// Pin for the tip down switch - D9
#define SW2 PIN_PD0
// Maximum sleep time for keep alive
#define SLEEP_TIMEOUT 86400

// Globals

volatile int sleepRestoreReason = 0; //

// Functions

// Sleep the device
int sleepDevice(uint32_t inDuration) {
  // Turn off all the ancillary hardware
  // Reset the verable to identify why we woke up
  sleepRestoreReason = 0;
  // Put the core hardware to sleep
  // If we are here we have just woken up and sleepRestoreReason will have been set if it was a switch
  // Return the reason we woke up
  return sleepRestoreReason;

// Send an update to the server
int sendTipUpdate(int inMessage) {

  if (!HttpClient.configure(DOMAIN, 80, false)) {"Failed to configure http client\r\n"));
  }"Configured to HTTP"));

  String postData = "{\"message\": \"" + String(inMessage) + "\"}";
  HttpResponse response ="/update/", postData.c_str());

  Log.infof(F("POST - HTTP status code: %u, data size: %u\r\n"),

  // Add some extra bytes for termination
  String body = HttpClient.readBody(response.data_size + 16);

  if (body != "") {
    Log.infof(F("Body: %s\r\n"), body.c_str());

  return true;


// Callback functions

// A function to complete the interupt callbacks
void switchCallback() {
  if (PORTD.INTFLAGS & PIN2_bm) {
      // Reset the interrupt flag

// Callback for tipper switch 1
void switch1Callback(void) {
  sleepRestoreReason = 1;

// Callback for tipper switch 3
void switch2Callback(void) {
  sleepRestoreReason = 2;

// Callback for the debugging button (SW0)
void switch3Callback(void) {
  sleepRestoreReason = 3;

// Main code

void setup() {
  // Start the log for debugging

  // Initalise the hardware
  LedCtrl.begin();  // LEDs
  Veml3328.begin(); // Light sensor
  Mcp9808.begin();  // Temprature sensor

  // Alow the modem and the CPU to be powered down
  // Note that the networks in the UK do not currenlty support the power save feature

  // Enable the switches and hook in the callbacks
  pinConfigure(SW1, PIN_DIR_INPUT | PIN_PULLUP_ON);
  attachInterrupt(SW1, switch1Callback, FALLING);
  pinConfigure(SW2, PIN_DIR_INPUT | PIN_PULLUP_ON);
  attachInterrupt(SW2, switch2Callback, FALLING);
  pinConfigure(SW0, PIN_DIR_INPUT | PIN_PULLUP_ON);
  attachInterrupt(SW0, switch3Callback, FALLING);

  // Make the lights flash, becasue we can
  // That and debugging. Yes, we are usig a visual indicator for debuggind and totllay not becuase it looks cool

  // Start LTE modem and connect to the operator
  if (!Lte.begin()) {
    Log.error(F("Failed to connect to the operator"));

  Log.infof(F("Connected to operator: %s\r\n"), Lte.getOperator().c_str());

void loop() {
  // Sleep the device until somthing happens
  int wakeReason = sleepDevice(SLEEP_TIMEOUT);
  Log.infof(F("Wake Reason: %d\r\n"), wakeReason);

  // If we are here somthing must have happeed so report it to the server



Alistair MacDonald

Alistair MacDonald

5 projects • 2 followers