@al1fch Hi,
try the code below (install the latest ArduinoBLE library through Library Manager).
/*
* GUI-O Basic BLE example for Arduino UNO R4 WiFi
*
* Uses the ArduinoBLE library and Nordic UART Service (NUS) UUIDs.
*
* Connect an LED (with a suitable series resistor) to PWM pin D9.
* The onboard LED is not used because brightness control requires PWM.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <ArduinoBLE.h>
namespace led {
constexpr uint8_t PIN = 9; // UNO R4 WiFi PWM-capable pin
}
namespace uuid {
constexpr char SERVICE[] = "6E400001-B5A3-F393-E0A9-E50E24DCCA9E";
constexpr char RX[] = "6E400002-B5A3-F393-E0A9-E50E24DCCA9E";
constexpr char TX[] = "6E400003-B5A3-F393-E0A9-E50E24DCCA9E";
}
namespace ble {
// A 20-byte payload works without depending on a larger negotiated MTU.
constexpr size_t NOTIFY_CHUNK_SIZE = 20;
constexpr int RX_BUFFER_SIZE = 512;
}
void parseGuioMsg(const String &msg);
void sendMsg(const String &msg);
BLEService nusService(uuid::SERVICE);
// GUI-O writes commands to RX.
BLECharacteristic rxCharacteristic(
uuid::RX,
BLEWrite | BLEWriteWithoutResponse,
ble::RX_BUFFER_SIZE
);
// UNO R4 sends GUI commands through TX notifications.
BLECharacteristic txCharacteristic(
uuid::TX,
BLENotify,
ble::NOTIFY_CHUNK_SIZE
);
bool wasConnected = false;
void setup() {
Serial.begin(115200);
pinMode(led::PIN, OUTPUT);
analogWrite(led::PIN, 0);
if (!BLE.begin()) {
Serial.println("Failed to initialize BLE!");
while (true) {
delay(1000);
}
}
BLE.setLocalName("BasicBLE_NUS");
BLE.setDeviceName("BasicBLE_NUS");
BLE.setAdvertisedService(nusService);
nusService.addCharacteristic(rxCharacteristic);
nusService.addCharacteristic(txCharacteristic);
BLE.addService(nusService);
BLE.advertise();
Serial.println("BLE advertising started.");
}
void loop() {
BLE.poll();
BLEDevice central = BLE.central();
const bool connected = central && central.connected();
if (connected && !wasConnected) {
Serial.print("Connected to: ");
Serial.println(central.address());
wasConnected = true;
}
if (!connected && wasConnected) {
Serial.println("Disconnected!");
wasConnected = false;
// Explicitly resume advertising for reliable reconnection.
BLE.advertise();
}
if (connected && rxCharacteristic.written()) {
const int length = rxCharacteristic.valueLength();
if (length > 0) {
String msg;
msg.reserve(length);
const uint8_t *value = rxCharacteristic.value();
for (int i = 0; i < length; ++i) {
msg += static_cast<char>(value[i]);
}
parseGuioMsg(msg);
}
}
}
/***************************/
/* IMPLEMENT YOUR GUI HERE */
/***************************/
void sendMsg(const String &msg) {
if (!wasConnected) {
return;
}
const uint8_t *data = reinterpret_cast<const uint8_t *>(msg.c_str());
size_t remaining = msg.length();
while (remaining > 0) {
const size_t chunkLength =
remaining > ble::NOTIFY_CHUNK_SIZE
? ble::NOTIFY_CHUNK_SIZE
: remaining;
if (!txCharacteristic.writeValue(data, chunkLength)) {
Serial.println("Failed to send BLE notification.");
return;
}
data += chunkLength;
remaining -= chunkLength;
BLE.poll();
delay(10);
}
}
void parseGuioMsg(const String &msg) {
if (msg.startsWith("@init")) {
Serial.println("GUI-O app is requesting INITIALIZATION!");
// Clear screen and set background.
sendMsg("@cls\r\n");
sendMsg("@guis BGC:#FFFFFF\r\n");
delay(100);
// Initialize simple example GUI.
sendMsg("|LB UID:title X:50 Y:15 TXT:\"Simple light switch\" FFA:\"font8\" FSZ:3.5\r\n");
sendMsg("|LB UID:tap_me X:50 Y:70 TXT:\"TAP ME!\" FFA:\"font8\" FSZ:3 FFA:\"font5\"\r\n");
sendMsg("|CB UID:brightness X:50 Y:50 W:90 BTH:5 HAH:8 HAW:8 VIS:0 STA:135 ENA:45 FGC:#000000 SFGC:#FFFF00 BGC:#CBCBCB\r\n");
sendMsg("|IM UID:light_off X:50 Y:50 IP:\"https://i.imgur.com/3VbsS0Z.png\" VIS:1\r\n");
sendMsg("|IM UID:light_on X:50 Y:50 IP:\"https://i.imgur.com/gNdck9A.png\" VIS:0\r\n");
}
else if (msg.startsWith("@light_off")) {
Serial.println("GUI-O app is requesting LIGHT ON!");
sendMsg("@light_off VIS:0\r\n");
sendMsg("@light_on VIS:1\r\n");
sendMsg("@brightness VIS:1 VAL:100\r\n");
analogWrite(led::PIN, 255);
}
else if (msg.startsWith("@light_on")) {
Serial.println("GUI-O app is requesting LIGHT OFF!");
sendMsg("@light_off VIS:1\r\n");
sendMsg("@light_on VIS:0\r\n");
sendMsg("@brightness VIS:0 VAL:0\r\n");
analogWrite(led::PIN, 0);
}
else if (msg.startsWith("@brightness")) {
const int idx = msg.indexOf(' ');
if (idx > 0) {
const int val = msg.substring(idx + 1).toInt();
if (val >= 0 && val <= 100) {
Serial.print("GUI-O app is requesting LIGHT BRIGHTNESS: ");
Serial.println(val);
const int pwmValue = map(val, 0, 100, 0, 255);
analogWrite(led::PIN, pwmValue);
}
}
}
}
I just used Chat to port the code from ESP32 on the GUI-O website. Should work...
Best regards,
Kl3m3n


