#include <M5GFX.h>
#include <M5Unified.h>
#include <M5_Scales.h>
M5Canvas canvas(&M5.Display);
M5_Scales scales;
constexpr uint8_t COLOR_COUNT = 3;
const uint32_t colorList[COLOR_COUNT] = {0xFF0000, 0x00FF00, 0x0000FF};
const char *const colorNames[COLOR_COUNT] = {"RED", "GREEN", "BLUE"};
const uint16_t colorBorders[COLOR_COUNT] = {TFT_RED, TFT_GREEN, TFT_BLUE};
constexpr int16_t BUTTON_MARGIN = 4;
constexpr int16_t BUTTON_GAP = 4;
constexpr int16_t BUTTON_HEIGHT = 46;
constexpr uint32_t SCREEN_UPDATE_INTERVAL_MS = 100;
int16_t buttonWidth = 0;
int16_t buttonY = 0;
bool ledSync = false;
uint8_t colorIndex = 2;
uint32_t lastScreenUpdate = 0;
bool forceScreenUpdate = true;
int16_t getButtonX(uint8_t index) {
return BUTTON_MARGIN + index * (buttonWidth + BUTTON_GAP);
}
int8_t getTouchedButton(int16_t x, int16_t y) {
if (y < buttonY || y >= buttonY + BUTTON_HEIGHT)
return -1;
for (uint8_t i = 0; i < 3; ++i) {
const int16_t buttonX = getButtonX(i);
if (x >= buttonX && x < buttonX + buttonWidth)
return i;
}
return -1;
}
void drawButton(uint8_t index, const char *title, const char *value,
uint16_t fillColor, uint16_t borderColor) {
const int16_t x = getButtonX(index);
canvas.fillRoundRect(x, buttonY, buttonWidth, BUTTON_HEIGHT, 4, fillColor);
canvas.drawRoundRect(x, buttonY, buttonWidth, BUTTON_HEIGHT, 4, borderColor);
canvas.drawRoundRect(x + 1, buttonY + 1, buttonWidth - 2, BUTTON_HEIGHT - 2,
3, borderColor);
canvas.setFont(&fonts::Font2);
canvas.setTextSize(1);
canvas.setTextDatum(textdatum_t::middle_center);
canvas.setTextColor(TFT_WHITE);
canvas.drawString(title, x + buttonWidth / 2, buttonY + 13);
canvas.drawString(value, x + buttonWidth / 2, buttonY + 33);
}
void drawScreen() {
canvas.fillSprite(TFT_BLACK);
canvas.setFont(&fonts::FreeMonoBold9pt7b);
canvas.setTextSize(1);
canvas.setTextDatum(textdatum_t::top_left);
canvas.setTextColor(TFT_WHITE);
const int weight = scales.getWeight();
const uint32_t adc = scales.getRawADC();
const bool unitButtonPressed = scales.getBtnStatus();
const uint8_t buttonCount = scales.getBtnPressedCount();
const uint8_t longPressCount = scales.getBtnLongPressedCount();
const uint32_t ledColor = scales.getLEDColor();
canvas.drawCenterString("Unit Scales Status", 160, 5);
canvas.drawString("WEIGHT: " + String(weight) + " g", 8, 28);
canvas.drawString("RAW ADC: " + String(adc), 8, 50);
canvas.drawString("UNIT BUTTON: " +
String(unitButtonPressed ? "PRESSED" : "RELEASED"),
8, 72);
canvas.drawString("BUTTON COUNT: " + String(buttonCount), 8, 94);
canvas.drawString("LONG PRESS: " + String(longPressCount), 8, 116);
canvas.drawString("LED COLOR: 0x" + String(ledColor, HEX), 8, 138);
canvas.drawString("LED SYNC: " + String(ledSync ? "ON" : "OFF"), 8, 160);
drawButton(0, "LED SYNC", ledSync ? "ON" : "OFF",
ledSync ? TFT_DARKGREEN : TFT_DARKGREY,
ledSync ? TFT_GREEN : TFT_LIGHTGREY);
drawButton(1, "SET", "OFFSET", TFT_DARKCYAN, TFT_CYAN);
drawButton(2, "COLOR", colorNames[colorIndex], TFT_DARKGREY,
colorBorders[colorIndex]);
canvas.pushSprite(0, 0);
}
void handleTouch() {
const auto touch = M5.Touch.getDetail();
if (!touch.wasClicked())
return;
switch (getTouchedButton(touch.x, touch.y)) {
case 0: {
const bool newLedSync = !ledSync;
if (scales.setLEDSyncWeight(newLedSync)) {
ledSync = newLedSync;
if (!ledSync) {
scales.setLEDColor(colorList[colorIndex]);
}
Serial.printf("LED Sync: %s\n", ledSync ? "ON" : "OFF");
} else {
Serial.println("Failed to change LED Sync");
}
break;
}
case 1:
if (scales.setOffset()) {
Serial.println("Offset set to current ADC value");
} else {
Serial.println("Failed to set offset");
}
break;
case 2: {
const uint8_t newColorIndex = (colorIndex + 1) % COLOR_COUNT;
if (scales.setLEDColor(colorList[newColorIndex])) {
colorIndex = newColorIndex;
Serial.printf("LED color: %s\n", colorNames[colorIndex]);
} else {
Serial.println("Failed to change LED color");
}
break;
}
default:
return;
}
forceScreenUpdate = true;
}
void showConnectionError(const char *message) {
canvas.fillSprite(TFT_BLACK);
canvas.setFont(&fonts::FreeMonoBold9pt7b);
canvas.setTextDatum(textdatum_t::middle_center);
canvas.setTextColor(TFT_RED);
canvas.drawString(message, canvas.width() / 2, canvas.height() / 2);
canvas.pushSprite(0, 0);
}
void setup() {
auto config = M5.config();
config.clear_display = true;
M5.begin(config);
Serial.begin(115200);
M5.Display.setRotation(1);
canvas.setColorDepth(16);
canvas.createSprite(M5.Display.width(), M5.Display.height());
buttonWidth = (M5.Display.width() - BUTTON_MARGIN * 2 - BUTTON_GAP * 2) / 3;
buttonY = M5.Display.height() - BUTTON_MARGIN - BUTTON_HEIGHT;
Wire.end();
while (!scales.begin(&Wire, EX_SDA, EX_SCL, M5_SCALES_DEFAULT_ADDR)) {
showConnectionError("UNIT SCALES CONNECT ERROR");
Serial.println("Unit Scales connect error");
delay(1000);
}
bool initialized = true;
initialized &= scales.setLEDSyncWeight(ledSync);
initialized &= scales.setBtnOffsetControl(false);
initialized &= scales.setLEDColor(colorList[colorIndex]);
Serial.println(initialized ? "Unit Scales initialized"
: "Unit Scales initialization error");
drawScreen();
}
void loop() {
M5.update();
handleTouch();
const uint32_t now = millis();
if (forceScreenUpdate ||
now - lastScreenUpdate >= SCREEN_UPDATE_INTERVAL_MS) {
drawScreen();
lastScreenUpdate = now;
forceScreenUpdate = false;
}
delay(10);
}