Hackster is hosting Hackster Holidays, Ep. 6: Livestream & Giveaway Drawing. Watch previous episodes or stream live on Monday!Stream Hackster Holidays, Ep. 6 on Monday!
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 hours468

Things used in this project

Hardware components

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

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)

Story

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.

Schematics

Tipper Tracker Wiring Diagram

Code

Tipper Tracker Firmware

Arduino
/**

   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 "www.example.com/tippertracker/APIendpoint"

// 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
  Veml3328.shutdown();
  Mcp9808.shutdown();
  // Reset the verable to identify why we woke up
  sleepRestoreReason = 0;
  // Put the core hardware to sleep
  LowPower.powerDown(inDuration);
  // 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)) {
    Log.info(F("Failed to configure http client\r\n"));
  }

  Log.info(F("Configured to HTTP"));

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

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

  // 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
      PORTD.INTFLAGS = PIN2_bm;
  }
}

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

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

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


// Main code

void setup() {
  
  // Start the log for debugging
  Log.begin(115200);
  Log.info(F("Starting"));

  // 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
  LowPower.configurePowerDown();

  // 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
  LedCtrl.startupCycle();

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

  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
  sendTipUpdate(wakeReason);

}

Credits

Alistair MacDonald

Alistair MacDonald

6 projects • 3 followers

Comments