mirror of
https://github.com/meshtastic/firmware.git
synced 2025-12-29 14:10:53 +00:00
WIP: add NAU7802 based scale controller. (#4092)
* WIP: add NAU7802 based scale controller. Needs proto commit * WIP: add NAU7802 based scale controller. Needs proto commit * telemetry uses kg, scale internally g * add sensor calibration setters
This commit is contained in:
143
src/modules/Telemetry/Sensor/NAU7802Sensor.cpp
Normal file
143
src/modules/Telemetry/Sensor/NAU7802Sensor.cpp
Normal file
@@ -0,0 +1,143 @@
|
||||
#include "configuration.h"
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "FSCommon.h"
|
||||
#include "NAU7802Sensor.h"
|
||||
#include "TelemetrySensor.h"
|
||||
#include <pb_decode.h>
|
||||
#include <pb_encode.h>
|
||||
|
||||
meshtastic_Nau7802Config nau7802config = meshtastic_Nau7802Config_init_zero;
|
||||
|
||||
NAU7802Sensor::NAU7802Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_NAU7802, "NAU7802") {}
|
||||
|
||||
int32_t NAU7802Sensor::runOnce()
|
||||
{
|
||||
LOG_INFO("Init sensor: %s\n", sensorName);
|
||||
if (!hasSensor()) {
|
||||
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
|
||||
}
|
||||
status = nau7802.begin(*nodeTelemetrySensorsMap[sensorType].second);
|
||||
nau7802.setSampleRate(NAU7802_SPS_320);
|
||||
if (!loadCalibrationData()) {
|
||||
LOG_ERROR("Failed to load calibration data\n");
|
||||
}
|
||||
nau7802.calibrateAFE();
|
||||
LOG_INFO("Offset: %d, Calibration factor: %.2f\n", nau7802.getZeroOffset(), nau7802.getCalibrationFactor());
|
||||
return initI2CSensor();
|
||||
}
|
||||
|
||||
void NAU7802Sensor::setup() {}
|
||||
|
||||
bool NAU7802Sensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||
{
|
||||
LOG_DEBUG("NAU7802Sensor::getMetrics\n");
|
||||
nau7802.powerUp();
|
||||
// Wait for the sensor to become ready for one second max
|
||||
uint32_t start = millis();
|
||||
while (!nau7802.available()) {
|
||||
delay(100);
|
||||
if (millis() - start > 1000) {
|
||||
nau7802.powerDown();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Check if we have correct calibration values after powerup
|
||||
LOG_DEBUG("Offset: %d, Calibration factor: %.2f\n", nau7802.getZeroOffset(), nau7802.getCalibrationFactor());
|
||||
measurement->variant.environment_metrics.weight = nau7802.getWeight() / 1000; // sample is in kg
|
||||
nau7802.powerDown();
|
||||
return true;
|
||||
}
|
||||
|
||||
void NAU7802Sensor::calibrate(float weight)
|
||||
{
|
||||
nau7802.calculateCalibrationFactor(weight * 1000, 64); // internal sample is in grams
|
||||
if (!saveCalibrationData()) {
|
||||
LOG_WARN("Failed to save calibration data\n");
|
||||
}
|
||||
LOG_INFO("Offset: %d, Calibration factor: %.2f\n", nau7802.getZeroOffset(), nau7802.getCalibrationFactor());
|
||||
}
|
||||
|
||||
AdminMessageHandleResult NAU7802Sensor::handleAdminMessage(const meshtastic_MeshPacket &mp, meshtastic_AdminMessage *request,
|
||||
meshtastic_AdminMessage *response)
|
||||
{
|
||||
AdminMessageHandleResult result;
|
||||
|
||||
switch (request->which_payload_variant) {
|
||||
case meshtastic_AdminMessage_set_scale_tag:
|
||||
if (request->set_scale == 0) {
|
||||
this->tare();
|
||||
LOG_DEBUG("Client requested to tare scale\n");
|
||||
} else {
|
||||
this->calibrate(request->set_scale);
|
||||
LOG_DEBUG("Client requested to calibrate to %d kg\n", request->set_scale);
|
||||
}
|
||||
result = AdminMessageHandleResult::HANDLED;
|
||||
break;
|
||||
|
||||
default:
|
||||
result = AdminMessageHandleResult::NOT_HANDLED;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void NAU7802Sensor::tare()
|
||||
{
|
||||
nau7802.calculateZeroOffset(64);
|
||||
if (!saveCalibrationData()) {
|
||||
LOG_WARN("Failed to save calibration data\n");
|
||||
}
|
||||
LOG_INFO("Offset: %d, Calibration factor: %.2f\n", nau7802.getZeroOffset(), nau7802.getCalibrationFactor());
|
||||
}
|
||||
|
||||
bool NAU7802Sensor::saveCalibrationData()
|
||||
{
|
||||
if (FSCom.exists(nau7802ConfigFileName) && !FSCom.remove(nau7802ConfigFileName)) {
|
||||
LOG_WARN("Can't remove old state file\n");
|
||||
}
|
||||
auto file = FSCom.open(nau7802ConfigFileName, FILE_O_WRITE);
|
||||
nau7802config.zeroOffset = nau7802.getZeroOffset();
|
||||
nau7802config.calibrationFactor = nau7802.getCalibrationFactor();
|
||||
bool okay = false;
|
||||
if (file) {
|
||||
LOG_INFO("%s state write to %s.\n", sensorName, nau7802ConfigFileName);
|
||||
pb_ostream_t stream = {&writecb, &file, meshtastic_Nau7802Config_size};
|
||||
|
||||
if (!pb_encode(&stream, &meshtastic_Nau7802Config_msg, &nau7802config)) {
|
||||
LOG_ERROR("Error: can't encode protobuf %s\n", PB_GET_ERROR(&stream));
|
||||
} else {
|
||||
okay = true;
|
||||
}
|
||||
file.flush();
|
||||
file.close();
|
||||
} else {
|
||||
LOG_INFO("Can't write %s state (File: %s).\n", sensorName, nau7802ConfigFileName);
|
||||
}
|
||||
return okay;
|
||||
}
|
||||
|
||||
bool NAU7802Sensor::loadCalibrationData()
|
||||
{
|
||||
auto file = FSCom.open(nau7802ConfigFileName, FILE_O_READ);
|
||||
bool okay = false;
|
||||
if (file) {
|
||||
LOG_INFO("%s state read from %s.\n", sensorName, nau7802ConfigFileName);
|
||||
pb_istream_t stream = {&readcb, &file, meshtastic_Nau7802Config_size};
|
||||
if (!pb_decode(&stream, &meshtastic_Nau7802Config_msg, &nau7802config)) {
|
||||
LOG_ERROR("Error: can't decode protobuf %s\n", PB_GET_ERROR(&stream));
|
||||
} else {
|
||||
nau7802.setZeroOffset(nau7802config.zeroOffset);
|
||||
nau7802.setCalibrationFactor(nau7802config.calibrationFactor);
|
||||
okay = true;
|
||||
}
|
||||
file.close();
|
||||
} else {
|
||||
LOG_INFO("No %s state found (File: %s).\n", sensorName, nau7802ConfigFileName);
|
||||
}
|
||||
return okay;
|
||||
}
|
||||
|
||||
#endif
|
||||
31
src/modules/Telemetry/Sensor/NAU7802Sensor.h
Normal file
31
src/modules/Telemetry/Sensor/NAU7802Sensor.h
Normal file
@@ -0,0 +1,31 @@
|
||||
#include "MeshModule.h"
|
||||
#include "configuration.h"
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "TelemetrySensor.h"
|
||||
#include <SparkFun_Qwiic_Scale_NAU7802_Arduino_Library.h>
|
||||
|
||||
class NAU7802Sensor : public TelemetrySensor
|
||||
{
|
||||
private:
|
||||
NAU7802 nau7802;
|
||||
|
||||
protected:
|
||||
virtual void setup() override;
|
||||
const char *nau7802ConfigFileName = "/prefs/nau7802.dat";
|
||||
bool saveCalibrationData();
|
||||
bool loadCalibrationData();
|
||||
|
||||
public:
|
||||
NAU7802Sensor();
|
||||
virtual int32_t runOnce() override;
|
||||
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
|
||||
void tare();
|
||||
void calibrate(float weight);
|
||||
AdminMessageHandleResult handleAdminMessage(const meshtastic_MeshPacket &mp, meshtastic_AdminMessage *request,
|
||||
meshtastic_AdminMessage *response) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#pragma once
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "MeshModule.h"
|
||||
#include "NodeDB.h"
|
||||
#include <utility>
|
||||
|
||||
@@ -42,6 +43,12 @@ class TelemetrySensor
|
||||
virtual void setup();
|
||||
|
||||
public:
|
||||
virtual AdminMessageHandleResult handleAdminMessage(const meshtastic_MeshPacket &mp, meshtastic_AdminMessage *request,
|
||||
meshtastic_AdminMessage *response)
|
||||
{
|
||||
return AdminMessageHandleResult::NOT_HANDLED;
|
||||
}
|
||||
|
||||
bool hasSensor() { return nodeTelemetrySensorsMap[sensorType].first > 0; }
|
||||
|
||||
virtual int32_t runOnce() = 0;
|
||||
|
||||
Reference in New Issue
Block a user