Capturing Temperature of Govee Bluetooth Sensors

I have an quite a few Govee temperature and humidity sensors. They’re reasonably priced, quite accurate, and they’re bluetooth LE. Yes, that allows them to sip power but at a cost that I cannot reach them when outside of home. Well, unless I get one of Govee hubs and connect them to cloud. But, is there a way to bypass the cloud and push all to my telegraf instance? Well, now there is!

First of all, why Telegraf? Obvious answer is because I have it already setup in my network and connected with my Grafana GUI. Longer answer is because I like the idea of telegraf. You have a centralized database and pushing to it is as easy as sending HTTP request. Everything is quite free-form and any mess you create is sorted out when data is displayed in Grafana.

Next question is, how? Well, I originally planned to roll my own script by abusing bluetoothctl scripting. However, during research I fount out that gentleman named William C Bonner already did pretty much the exact thing I wanted to. His GoveeBTTempLogger already both captures and decodes Govee temperature and humidity data.

And yes, there is no x64 package precompiled but, surprisingly, README.md instructions actually work. That said, I opted to build binaries a bit differently. This allowed me to install binary into /usr/local/bin/.

sudo apt install build-essential cmake git libbluetooth-dev libdbus-1-dev
git clone https://github.com/wcbonner/GoveeBTTempLogger.git
cd GoveeBTTempLogger
cmake -B ./build
sudo cmake --build ./build --target install

Once compiled, we can start application and, hopefully, see all the temperatures.

goveebttemplogger

And, if you just want to see the current values, that’s enough. If you check into README.md a bit more, you can also setup application to output web pages. Unfortunately, there is no telegraf output option. Or thankfully, since this gives me option to roll my own script around this nice tool.

What I ended up with is the following.

TG_HOST=<ip>
TG_PORT=<port>
TG_BUCKET=<bucket>
TG_USERNAME=<user>
TG_PASSWORD=<password>

while IFS= read -r LINE; do
  DATA=`echo "$LINE" | grep '(Temp)' | grep '(Humidity)' | grep '(Battery)'`
  if [ "$DATA" == "" ]; then continue; fi

  DEVICE=`echo $DATA | awk '{print $2}' | tr -d '[]'`
  TEMPERATURE=`echo $DATA | awk '{print $4}' | tr -dc '0-9.'`
  HUMIDITY=`echo $DATA | awk '{print $6}' | tr -dc '0-9.'`
  BATTERY=`echo $DATA | awk '{print $8}' | tr -dc '0-9.'`

  printf "%s %5s°C %4s%% %3s%%\n" $DEVICE $TEMPERATURE $HUMIDITY $BATTERY
  CONTENT="temp,device=$DEVICE temp=${TEMPERATURE},humidity=${HUMIDITY},battery=${BATTERY} `date +%s`"$'\n'
  CONTENT_LEN=$(echo -en ${CONTENT} | wc -c)
  echo -ne "POST /api/v2/write?u=$TG_USERNAME&p=$TG_PASSWORD&bucket=${TG_BUCKET}&precision=s HTTP/1.0\r\nHost: $TG_HOST\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: ${CONTENT_LEN}\r\n\r\n${CONTENT}" | nc -w 15 $TG_HOST $TG_PORT
done < <(/usr/local/bin/goveebttemplogger --passive)

This script goes over goveebttemplogger output and extracts device MAC address and its data. That data is then packed into Telegrafs line format and simply posted into nc as raw HTTP output. Not more difficult than wget or curl.

Wrapping this into a service so it runs in the background is an exercise left to the reader.