Squeak: GPS pet tracker

Squeak is a LoRaWAN GPS pet tracker with a very long battery life. It allows you to ask your pets to share their location

Public Chat
Similar projects worth following
Goals for Squeak:
- More than 2 months of battery life (GPS off, 15 minute uplinks)
- decent size for dogs & big-ish cats

There are many other GPS pet/asset trackers, some of them also using LoRa in one form or another. These all have their own advantages and drawbacks. Here are some of the ones I'm aware of:

LTE connectivity

LoRaWAN, very configurable

LoRaWAN, somewhat configurable

LoRa (LoRaWAN coming), very small, open source

LoRaWAN, just for Orange France, very small

Tracking platform

Squeak is growing to be an open-source platform for LoRaWAN GPS tracking. Its goal is to be small enough to be easily carried around by a pet and have such a long battery life that it's not a hassle to keep it working.

Latest hardware revision is smaller and has more features than the original prototype. A comprehensive comparison is in the following table, but the general functionality of the device is similar to the original, described further down.

------------------- Original description -------------------


The size is 38mm x 20mm x 12mm. This does not include battery and antenna


The tracker uses the RN2483 module from Microchip as an application processor, thanks to Microchip publishing the source code to the module. The general architecture of the tracker is the following:

The module is always powered by the top LDO but is kept in sleep most of the time. On request it can switch on the LDO to the GPS module and wait to get a fix that it can then uplink through LoRaWAN. The GPS module's RAM is always kept powered through its V_BACKUP line (not shown here) and there's also a battery voltage measurement circuit.


Project hardware available on EasyEDA.


Uplink data

Measurements are periodically reported through uplink messages that use the lowest data rate possible (DR0 - SF12BW125 in EU), to maximise the chances of a packet being picked up by a gateway. Packet structure is, in bytes:

[0] - Header: 0x80 - GPS off; 0x81 - GPS on for N transmissions then will be switched off; 0x82 - GPS switched on every M transmissions. GPS mode, N and M are set via downlink config messages

[1-2] - 16 bit counter of number of packets sent. Can be used to check if packets have been missed (e.g. bad network coverage)

[3] - Battery charge state, roughly in %

[4] - Temperature in deg. C. Signed int, 1 degree resolution.

[5-8] - Time of last valid GPS fix. 27 packed bits: (7 bits year), (4 bits month), (5 bits day), (5 bits hour), (6 bits minute)

[9-12] - GPS Latitude

[13-16] - GPS Longitude

Downlink data

Downlinks configure the behaviour - how often uplinks are sent and which of these uplinks should contain GPS measurements. Packet structure:

[0] - Uplink interval, in multiples of 2 minutes

[2] - GPS mode. 0x00 - GPS off; 0x01 - GPS on for N transmissions then will be switched off; 0x02 - GPS switched on every M transmissions

[3] - N or M, depending on GPS mode


The firmware is available on GitHub.

Cloud data service

For pet owners to actually interact with the tracker there's a Telegram bot that one can ask to share the location of the tracker

  • New hardware

    mihai.cuciuc02/28/2023 at 05:54 1 comment

    Switched to the Microchip WLR089 LoRa module and this brings more features. Full list of improvements:

    • ARM Cortex M0+ with 256 KB flash and 40KB RAM
    • Dual band, 868 MHz and 915 MHz
    • USB connectivity
    • On-module u.FL antenna connector so no RF path needs to be on my PCB
    • Switched to the Quectel LC86L GNSS module, capable of tracking GPS and also GLONASS
    • Added an Analog Devices ADXL362 low-power accelerometer for activity tracking
    • Added a software-controlled LED and a button
    • Added an on-board I2C temperature sensor for monitoring safe operating range of battery
    • Updating firmware is much easier through USB, using UF2 bootloader
    • Arduino compatibility is possible, as there are ports for the SAM R34 chip in the WLR089 module

    Some limitations that have been carried over from original prototype:

    • LC86L module requires a much larger ground plane, thus GPS antenna performance may be significantly reduced
    • LoRa antenna is packed very tightly in case close to many other components, thus performance at 868 MHz and 915 MHz is greatly reduced

  • Squeak firmware on GitHub

    mihai.cuciuc01/13/2023 at 06:06 0 comments

    You can find the Squeak firmware for the PIC18LF46K22 running in the RN2483 on GitHub. To build it you need MPLABX v5.50 and the free version of the XC8 v1.45 compiler.

    This should also work as a good starting point for simple applications running directly on the RN2483, as most of the fancy things that make up the RN2483 have been stripped out.

    The serial port available on the PCB header is available if you comment out #define MCP9701 in eusart1.h. If you have that definition you can use the serial port header for the temperature measurement chip.

    Microchip LoRaWAN stack

    The only change I made to the stock LoRaWAN stack provided by Microchip is the addition of the LORAWAN_CanSend() to lorawan.c, which reports if the stack can send a packet or not. The stack may be unable to tx because of duty cycle restrictions, and without LORAWAN_CanSend() the only way to tell is to actually transmit a packet. For Squeak this could be a problem if you just spent a lot of battery on getting a GPS fix and then cannot inform the user of this fresh location.

  • Battery testing

    mihai.cuciuc12/23/2022 at 08:35 0 comments

    Continuing on the trails of the battery life not being quite what was expected in the previous project log I checked the battery I used. The battery was one of these but I noticed it was a bit puffed. Discharging it overnight through a power 200 Ohm resistor yielded the following voltage curve.

    The resulting 250mAh capacity perfectly accounts for the difference in runtime. I also checked a new, unpuffed 400mAh battery bought in the same batch and that one yielded 375mAh, so I'm not that worried.

    As long as I have that curve I might as well check my assumptions on the voltage-to-charge-state LUT.

    On the left is the measured battery remaining capacity vs battery voltage, along with a linear fit that's easy to plug into the firmware. On the right is the estimation error given by this simple linear fit with respect to the charge state reported by the fit. So if the device reports 50% charge left, the actual remaining charge is ~46%. But as the error is within 5% of the true value between 10% and 100% I'll live with the linear fit.

    Comparing these values to the original LUT I was using it's obvious I was very wrong in using this chart, made specifically for high current LiPo batteries.

    The measurements for my battery of battery charge state vs voltage are waaaaay off from those given in the LiPo chart.

    Moving forward I'm confident that Squeak will provide a much more accurate battery level.

  • Power profiling

    mihai.cuciuc12/19/2022 at 05:42 0 comments

    In a previous project log I missed the mark substantially on battery life estimations. While I still don't have a conclusion, I wanted to confirm the tracker's power profile. My measurements so far were done with a cheapish multimeter, and they were:

    • Sleep: 9uA
    • Radio tx: 33mA
    • Radio rx: 14mA
    • GPS on: 35mA

    Here are updated values, taken with a DMM6500.

    Taking a closer look at the sleep current reveals the way the PIC18F sleeps for a long time: it has to wake up every 2 seconds to service its 16bit timer fed by a watch crystal.

    Averaging the currents drawn in different modes comes down to:

    • Sleep: 8.85uA
    • Radio tx: 28.9mA
    • Radio Rx: 14.2mA
    • GPS on: 26.5mA

    So this is actually lower than the initial measurements. I'm not bothering with the 3mA drawn in between Rx and Tx when the MCU is awake, as that is negligible compared to the time the GPS is on.

    So my wrong estimates on the battery capacity may still come from:

    • Lower than advertised battery capacity at 0.1C discharge rate
    • I'm measuring battery voltage wrong
    • I'm using a voltage-to-charge LUT that's not appropriate for the battery

  • Squeak Cloud Service

    mihai.cuciuc12/12/2022 at 04:56 0 comments

    Squeak uses LoRaWAN for connectivity but the data on the network has to make it to the pet owner. Solutions in the previous posts did get the job done but were rather hacky, having to go through Google Sheets or to configure Datacake for Squeak. These also required users to poll the data for any location updates.

    The Squeak Cloud Service is a custom platform that uses AWS for data storage and for the business logic and a Telegram bot to allow owners to interact with their hardware.

    Bot commands

    • /loc <tracker name>
      will report the last status transmitted by the tracker and when this status was received. The last position measured is also provided as a shared location
    • /find <tracker name>
      triggers a downlink that will request a new GPS measurement to be made just for the next uplink. When the uplink is received the bot will share location
    • /gps_on <tracker name>
      turns on GPS measurements for uplinks. For each received uplink the bot will share the new location
    • /gps_off <tracker name>
      turns off GPS measurements for uplinks

    The user is contacted by the bot in any of the following cases:

    • a packet with a GPS measurement has been received
    • tracker battery <= 20%
    • tracker temperature >= 50 deg. C

  • Adding a logo

    mihai.cuciuc12/05/2022 at 06:16 0 comments

    I could not resist the temptation to add a logo to the case. Also made the case a bit taller to remove the humps for the GPS antenna and temperature sensor.

  • (Almost) No code data logging to Google Sheets

    mihai.cuciuc11/29/2022 at 05:13 0 comments

    Helium has this cool integration to Google Sheets through Google Forms. Once you register the tracker on the Helium console you can follow this guide on how to dump the data into Google Sheets.

    The only code you need to massage the data is in the custom decoder. For example if you just want to fill counter, battery and temperature values in your spreadsheet this can be as simple as filling which bytes go where in the template built by the Helium console from your Google Form.

    function Decoder(bytes, port) {
      // TODO: Transform bytes to decoded payload below
      var decodedPayload = {
        "battery": bytes[3],
        "counter": (bytes[1] << 8) + bytes[2],
        "temperature": bytes[4]
      // END TODO
      return Serialize(decodedPayload)

    You can add fancier fields, like latitude and longitude by decoding them similarly to how you do it for Datacake.

    Then you can plot your data in Google Sheets or download the Excel file and do it locally.

  • Adding a temperature sensor

    mihai.cuciuc11/28/2022 at 06:04 0 comments

    For testing the performance of the tracker I'd want to leave one in my car. But it contains a rechargable lithium battery and I'd feel much better if it could alert me if the temperature is outside the battery's recommended range.

    To make no changes on the PCB I repurposed a UART header I used for debugging to accomodate a TO-92 Microchip MCP9701. This was possible since the UART pins can also be used as ADC inputs on the PIC18F46K22 used in the RN2483.

    So I used one pin for reading the voltage from the MCP9701 and the other for turning it on or off. It's fairly low power (6uA or so) so it can safely be powered from a GPIO.

    Now every uplink contains temperature data that can trigger an alert.

  • Magnetic charging connector

    mihai.cuciuc11/25/2022 at 05:45 0 comments

    While I initially considered a USB connector for charging the battery, I eventually settled on this magnetic connector. There are also 3D files to make designing it into the case real easy. The tracker is getting heavy though, at 36 g (1.27 oz).

  • Datacake integration: Seeing Squeak on a map

    mihai.cuciuc11/20/2022 at 18:05 0 comments

    Datacake can be used to integrate and visualize IoT data. It's a paid service, but you get two devices for free. It readily integrates with The Things Network and you can easily have a web interface for the Squeak tracker.

    After registering Squeak in the The Things Network application, define a webhook for bidirectional communication with Datacake.

    Use a custom payload decoder for Datacake to make sense of what's being sent

    function Decoder(payload, port) {
        var decoded = {};
        decoded.counter =  (payload[1] << 8) | payload[2];
        decoded.battery = payload[3];
        decoded.temperature = payload[4];
        gpsYy = payload[5] >> 1;
        gpsMo = ((payload[5] & 0x01) << 3) | ((payload[6] & 0xE0) >> 5);
        gpsDd = payload[6] & 0x1F;
        gpsHh = (payload[7] & 0xF8) >> 3;
        gpsMi = ((payload[7] & 0x07) << 3) | ((payload[8] & 0xE0) >> 5);
        lat = ((payload[9] << 24) | (payload[10] << 16) | (payload[11] << 8) | payload[12]);
        lng = ((payload[13] << 24) | (payload[14] << 16) | (payload[15] << 8) | payload[16]);
        gpsTs = 0;
        gpsLat = -1000;
        gpsLon = -1000;
        if ((lat > -500) && (lng > -500))
            ts = new Date(2000 + gpsYy, gpsMo - 1, gpsDd, gpsHh, gpsMi, 0, 0);
            //console.log(ts.getTimezoneOffset());  // Maybe one needs to adjust for timezones here. For now it looks like Datacake runs on the UTC timezone which is great.
            gpsTs = ts.getTime() / 1000;
            gpsLatF = lat / 10000000.0;
            gpsLatDD = ~~gpsLatF;
            gpsLatMM = (gpsLatF - gpsLatDD) * 100.0/60.0;
            gpsLat = gpsLatDD + gpsLatMM;
            gpsLonF = lng / 10000000.0;
            gpsLonDD = ~~gpsLonF;
            gpsLonMM = (gpsLonF - gpsLonDD) * 100.0/60.0;
            gpsLon = gpsLonDD + gpsLonMM;
        decoded.timestamp = gpsTs;
        decoded.location = "(" + gpsLat + "," + gpsLon + ")";
        return decoded;

    Add fields for the values you're interested in from the decoded structure. Things like battery, location, etc. Also add a downlink configuration to be able to send a command to turn on the GPS.

    function Encoder(measurements, port) {
        return [0x02, 0x01, 0x03];

    This payload says it should try to send an uplink every 4 minutes, and the GPS should be on for the following 3 packets. A UI is fairly easy to build up once you have the decoder, fields, and encoder set up.

View all 16 project logs

Enjoy this project?



Brock wrote 04/10/2024 at 05:31 point

Has this project advanced since the last comment dates of about a year ago?  I'm wondering whether the explosion of Meshtastic nodes might change the thinking around how to move data?  Compatible devices are getting both cheaper and less power hungry.

  Are you sure? yes | no

mihai.cuciuc wrote 04/11/2024 at 04:47 point

Hi, Brock! On the hardware side I tried updating both GPS and LoRa antennas. That decreased the weight to about 21g. I experimented a little with adding peer-to-peer communication without breaking the existing LoRaWAN connection which worked quite nicely but range in peer-to-peer mode was pretty bad.

I eventually came to terms with the thought that LoRaWAN is probably not the right infrastructure for a pet tracker. But I provided some modules to friends that are interested in other asset tracking applications.

Meshtastic looks like an awesome technology, I'm also eager to see if it gets implemented as the underlying data transport for applications -- I have a few in mind myself!

  Are you sure? yes | no

George wrote 03/31/2023 at 20:51 point

Have you ever implemented this on any off-the-shelf modules or just on your custom PCB?  Something like

  Are you sure? yes | no

mihai.cuciuc wrote 04/13/2023 at 04:11 point

Hi, George! For initial prototyping I used the Microchip LoRa Pictail connected with jumper wires to a standard GPS module. But I switched to custom PCBs quite soon afterwards.

The application logic should not be *too* hard to port to a different platform, but I did end up adding some functionality to the LoRaWAN stack on the Microchip module. This is because I needed to know at the application layer if it is possible to transmit a LoRaWAN uplink or I have no free channels (due to duty cycle limitations). Only if it is possible to send an uplink do I turn the GPS on for a measurement.

  Are you sure? yes | no

Cody wrote 12/21/2022 at 04:09 point

I’ve actually been using the Fi Collar for about 6 months and HATE it. This looks like a very good framework for an alternative to those. Can’t wait to give this a try over the holidays. 

  Are you sure? yes | no

CheMaRy wrote 12/19/2022 at 23:13 point

I recently saw Ai-Thinker has released new boards Ra-08 that are essentially a ASR6601 MCU with Semtech SX1262. They are really small and cheap, the problem is they only have 128KB FLASH and 16KB SRAM and probably you need more for LoRaWAN implementation.

  Are you sure? yes | no

mihai.cuciuc wrote 12/20/2022 at 05:20 point

Thanks for the heads-up! I think there's no problem fitting a LoRaWAN stack on that kind of resources, the code I'm running now is 55kB (on the PIC18 architecture). Recent tests with the WLR089U0 module from Microchip (similar in size and price to the RA-08) have the code sitting at about 122kB, so it's doable.

  Are you sure? yes | no

Benjamin König wrote 11/20/2022 at 11:24 point

Looks good. Seems you a pretty far already. I hope you can sort out these power drain issues. That RN2483 is a bit bulky though. Have you have also looked at the AcSiP S76G?

  Are you sure? yes | no

mihai.cuciuc wrote 11/20/2022 at 14:53 point

Thanks, I'm having a blast working on it. Wow, the AcSiP S76G looks really good but it seems it's discontinued. I also don't feel confident enough to integrate any of the RF part on the PCB. Moving forward I'm looking at the smaller WLR089U0 and maybe a Quectel L96 GPS.

  Are you sure? yes | no

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates