Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/remote_scales.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,14 @@ std::string RemoteScales::byteArrayToHexString(const uint8_t* byteArray, size_t
return hexString;
}

uint32_t RemoteScales::millis() {
#ifdef ARDUINO
return ::millis();
#elif defined(ESP_PLATFORM)
return esp_timer_get_time() / 1000;
#endif
return 0;
}

// ---------------------------------------------------------------------------------------
// ------------------------ RemoteScales methods ------------------------------
Expand Down
5 changes: 4 additions & 1 deletion src/remote_scales.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#pragma once
#ifdef ARDUINO
#include <Arduino.h>
#endif
#include <NimBLEDevice.h>
#include <Arduino.h>
#include <vector>
#include <memory>
#include <lru_cache.h>
Expand Down Expand Up @@ -52,6 +54,7 @@ class RemoteScales {
void log(std::string msgFormat, ...);
std::string byteArrayToHexString(const uint8_t* byteArray, size_t length);

uint32_t millis();
private:
using WeightCallback = void (*)(float);

Expand Down
1 change: 0 additions & 1 deletion src/scales/acaia.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#pragma once
#include "remote_scales.h"
#include "remote_scales_plugin_registry.h"
#include <Arduino.h>
#include <NimBLEDevice.h>
#include <NimBLEUtils.h>
#include <NimBLEScan.h>
Expand Down
1 change: 0 additions & 1 deletion src/scales/bookoo.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#pragma once
#include "remote_scales.h"
#include "remote_scales_plugin_registry.h"
#include <Arduino.h>
#include <NimBLEDevice.h>
#include <NimBLEUtils.h>
#include <NimBLEScan.h>
Expand Down
1 change: 0 additions & 1 deletion src/scales/eclair.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#pragma once
#include "remote_scales.h"
#include "remote_scales_plugin_registry.h"
#include <Arduino.h>
#include <NimBLEDevice.h>
#include <vector>
#include <memory>
Expand Down
134 changes: 134 additions & 0 deletions src/scales/tencent.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
#include "tencent.h"
#include <cstring>

// Initialize UUID constants
const NimBLEUUID TencentScales::DATA_SERVICE_UUID("FFE0");
const NimBLEUUID TencentScales::DATA_CHARACTERISTIC_UUID("FFE1");

TencentScales::TencentScales(const DiscoveredDevice& device) : RemoteScales(device) {}

bool TencentScales::connect() {
if (isConnected()) {
log("Already connected.\n");
return true;
}

if (!clientConnect()) {
clientCleanup();
return false;
}

if (!performConnectionHandshake()) {
clientCleanup();
return false;
}
setWeight(0.f);
return true;
}

void TencentScales::disconnect() {
clientCleanup();
}

bool TencentScales::isConnected() {
return clientIsConnected();
}

void TencentScales::update() {
if (markedForReconnection) {
log("Reconnecting...\n");
clientCleanup();
connect();
markedForReconnection = false;
}
else {
verifyConnected();
}
}

bool TencentScales::tare() {
if (!verifyConnected()) return false;
log("Tare command sent.\n");
uint8_t tareCommand[] = { CMD_TARE };
dataCharacteristic->writeValue(tareCommand, sizeof(tareCommand), true);
return true;
}

bool TencentScales::performConnectionHandshake() {
log("Performing handshake...\n");

service = clientGetService(DATA_SERVICE_UUID);
if (!service) {
log("Service not found.\n");
return false;
}

dataCharacteristic = service->getCharacteristic(DATA_CHARACTERISTIC_UUID);
if (!dataCharacteristic) {
log("Characteristic not found.\n");
return false;
}

if (dataCharacteristic->canNotify()) {
dataCharacteristic->subscribe(true, [this](NimBLERemoteCharacteristic* characteristic, uint8_t* data, size_t length, bool isNotify) {
notifyCallback(characteristic, data, length, isNotify);
});
}
else {
log("Notifications not supported.\n");
return false;
}

return true;
}
bool TencentScales::verifyConnected() {
if (markedForReconnection) {
return false;
}
if (!isConnected()) {
markedForReconnection = true;
return false;
}
return true;
}

void TencentScales::notifyCallback(NimBLERemoteCharacteristic* characteristic, uint8_t* data, size_t length, bool isNotify) {
log("Notification received.\n");
if (length < 11) {
log("Malformed data.\n");
return;
}
parseStatusUpdate(data, length);
}

void TencentScales::parseStatusUpdate(const uint8_t* data, size_t length) {

if (data[0] == 0xA7 && data[1] == 0x00 && data[2] == 0x24) {
if (data[3] == 0x0C && data[4] == 0x13 && length >= 18) {
float weight = static_cast<float>(parseWeight(data));
setWeight(weight);
log("Weight updated: %.1f g\n", weight);
}
}
}

float TencentScales::parseWeight(const uint8_t* data) {

bool isNegative = (data[7] >> 4) & 0x01;

uint32_t value = data[8] << 16 | data[9] << 8 | data[10];

if (isNegative) {
return -(value / 10.0f);
}

return value / 10.f;
}

uint8_t TencentScales::calculateChecksum(const uint8_t* data, size_t length) {
uint8_t checksum = 0;
for (size_t i = 0; i < length - 1; ++i) {
checksum += data[i];
}
return checksum;
}
62 changes: 62 additions & 0 deletions src/scales/tencent.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#pragma once
#include "remote_scales.h"
#include "remote_scales_plugin_registry.h"
#include <NimBLEDevice.h>

class TencentScales : public RemoteScales {
public:
TencentScales(const DiscoveredDevice& device);

bool tare() override;
bool isConnected() override;
bool connect() override;
void disconnect() override;
void update() override;

private:
NimBLERemoteService* service = nullptr;
NimBLERemoteCharacteristic* dataCharacteristic = nullptr;
uint32_t lastHeartbeat = 0;
bool markedForReconnection = false;

void notifyCallback(NimBLERemoteCharacteristic* characteristic, uint8_t* data, size_t length, bool isNotify);
bool performConnectionHandshake();
void toggleUnit();
void togglePrecision();
bool verifyConnected(void);
void parseStatusUpdate(const uint8_t* data, size_t length);
uint8_t calculateChecksum(const uint8_t* data, size_t length);
float parseWeight(const uint8_t* data);

// Constants specific to Tencent Scales
static const NimBLEUUID DATA_SERVICE_UUID;
static const NimBLEUUID DATA_CHARACTERISTIC_UUID;
static constexpr uint8_t CMD_TARE = 0x54;
static constexpr uint8_t CMD_TOGGLE_UNIT = 0x55;
static constexpr uint8_t CMD_TOGGLE_PRECISION = 0x44;
};


class TencentScalesPlugin {
public:
static void apply() {
RemoteScalesPlugin plugin;
plugin.id = "plugin-tencent";
plugin.handles = &TencentScalesPlugin::handles;
plugin.initialise = &TencentScalesPlugin::initialise;
RemoteScalesPluginRegistry::getInstance()->registerPlugin(plugin);
}

private:
static bool handles(const DiscoveredDevice& device) {
const std::string& deviceName = device.getName();
return !deviceName.empty()
&& (
deviceName.find("DSD TECH") == 0
);
}

static std::unique_ptr<RemoteScales> initialise(const DiscoveredDevice& device) {
return std::make_unique<TencentScales>(device);
}
};
2 changes: 1 addition & 1 deletion src/scales/timemore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ bool TimemoreScales::decodeAndHandleNotification() {
// E.g. 78 08 00 00 = 2168 / 10 = 216.8g

//float_t dripperWeight = dataBuffer[1] | (dataBuffer[2] << 8) | (dataBuffer[3] << 16) | (dataBuffer[4] << 24);
float_t scaleWeight = dataBuffer[5] | (dataBuffer[6] << 8) | (dataBuffer[7] << 16) | (dataBuffer[8] << 24);
uint32_t scaleWeight = dataBuffer[5] | (dataBuffer[6] << 8) | (dataBuffer[7] << 16) | (dataBuffer[8] << 24);

RemoteScales::setWeight(scaleWeight / 10.0f); // Convert to floating point
}
Expand Down
1 change: 0 additions & 1 deletion src/scales/timemore.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#pragma once
#include "remote_scales.h"
#include "remote_scales_plugin_registry.h"
#include <Arduino.h>
#include <NimBLEDevice.h>
#include <NimBLEUtils.h>
#include <NimBLEScan.h>
Expand Down
4 changes: 2 additions & 2 deletions src/scales/weighmybru.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ bool WeighMyBrewScales::performConnectionHandshake() {

sendNotificationRequest();
RemoteScales::log("Sent notification request\n");
lastHeartbeat = millis();
lastHeartbeat = RemoteScales::millis();
return true;
}

Expand All @@ -196,7 +196,7 @@ void WeighMyBrewScales::sendHeartbeat() {
return;
}

uint32_t now = millis();
uint32_t now = RemoteScales::millis();
if (now - lastHeartbeat < 2000) {
return;
}
Expand Down
1 change: 0 additions & 1 deletion src/scales/weighmybru.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#pragma once
#include "remote_scales.h"
#include "remote_scales_plugin_registry.h"
#include <Arduino.h>
#include <NimBLEDevice.h>
#include <NimBLEUtils.h>
#include <NimBLEScan.h>
Expand Down