Fredrik Erlandsson

Logo

PhD in Computer science, data scientist at Consid AB.

Getting the PunchTrough LightBlue Bean to work 2025

2025-06-04

I bought a couple of LightBlue Beans in 2014 but never got my way around to get them into use. Here are some notes on getting an development environment up and running in 2025 (most of the original links and resources are removed).

The patching of the Arduino binary does not work entirely as expected, the libraries are not installed in the correct path. So the contents of the folder /Applications/Bean\ Loader.app/Contents/Resources/Arduino/hardware/ needs to be copied into ~/Library/Arduino15/packages/arduino/hardware. After some struggle with permissions (modern OS X are super conservative on running downloaded apps and letting apps patch each other), I managed to get an example sketch to compile and flash via the BeanLoader.

Documentation is still available trough WayBack Machine https://web.archive.org/web/20171122094141/https://punchthrough.com/bean/reference

Other resources:

The main idea is to get my Beans to talk BTHome. With the intention that the Bean would advertise sensor readings from eg. DS18b20 sensors. This is the current code, note that it is still in progress (BTHome doesn’t see them):

#include <Bean.h>
#include <OneWire.h>
#include <DallasTemperature.h>

#define ONE_WIRE_BUS 2
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

// BTHome constants
const uint16_t BTHOME_UUID     = 0xFCD2;
const uint8_t BTHOME_TEMP_EXT  = 0x02; // External DS18B20
const uint8_t BTHOME_BATT_V    = 0x0A;
const uint8_t BTHOME_TEMP_INT  = 0x57; // Custom: internal temp
const uint8_t BTHOME_DEV_ID    = 0xFF;

const uint8_t DEVICE_ID        = 0x42; // Set unique per unit
const unsigned long SLEEP_MS   = 15UL * 60UL * 1000UL; // 15 minutes

void setup() {
  Bean.enableCustom();
  Bean.enableConfigSave(false);
  Bean.setAdvertisingInterval(100);
}

void loop() {
  sensors.begin();

  // Read external DS18B20
  sensors.requestTemperatures();
  float tempExtC = sensors.getTempCByIndex(0);
  int16_t tempExt = (int16_t)(tempExtC * 100); // 0.01 °C

  // Read internal Bean temp
  int8_t tempIntC = Bean.getTemperature();

  // Read battery voltage
  uint16_t battV = Bean.getBatteryVoltage();

  // Build BTHome BLE Advertisement
  uint8_t adv[30] = {0};
  uint8_t i = 0;

  // BLE flags
  adv[i++] = 0x02;
  adv[i++] = 0x01;
  adv[i++] = 0x06;

  // BTHome service data
  adv[i++] = 0x13;               // Length of following block: 19 bytes
  adv[i++] = 0x16;               // Service Data
  adv[i++] = lowByte(BTHOME_UUID);
  adv[i++] = highByte(BTHOME_UUID);

  // External temp
  adv[i++] = BTHOME_TEMP_EXT;
  adv[i++] = lowByte(tempExt);
  adv[i++] = highByte(tempExt);

  // Battery voltage
  adv[i++] = BTHOME_BATT_V;
  adv[i++] = lowByte(battV);
  adv[i++] = highByte(battV);

  // Internal temp
  adv[i++] = BTHOME_TEMP_INT;
  adv[i++] = tempIntC;

  // Device ID
  adv[i++] = BTHOME_DEV_ID;
  adv[i++] = DEVICE_ID;

  Bean.setLedGreen(255);

  // Broadcast advertisement
  Bean.setCustomAdvertisement(adv, i);
  Bean.enableAdvertising(true, 10 * 1000);         // advertise for 10s

  // Sleep deeply to conserve battery
  Bean.setLedGreen(0);
  Bean.sleep(SLEEP_MS);
}