Skip to content

Instantly share code, notes, and snippets.

@TheGreyDiamond
Last active December 15, 2022 21:05
Show Gist options
  • Save TheGreyDiamond/2a39ba01c009bc1e6beea151792ef918 to your computer and use it in GitHub Desktop.
Save TheGreyDiamond/2a39ba01c009bc1e6beea151792ef918 to your computer and use it in GitHub Desktop.
Moonside Lamp BLE Connector
/**
* A BLE controller for Moonside lamps, tested with a Moonside Lighthouse.
* It has some errors with reconnecting after loosing WiFi connection.
*/
#include "BLEDevice.h"
#include <WiFi.h>
#include <WiFiClient.h>
#include <WebServer.h>
#include <ArduinoOTA.h>
#include <ESPmDNS.h>
//#include "BLEScan.h"
const PROGMEM char* ssid = "ssid";
const PROGMEM char* password = "passwd";
WebServer server(80);
// The remote service we wish to connect to.
static PROGMEM BLEUUID serviceUUID("6e400001-b5a3-f393-e0a9-e50e24dcca9e");
// The characteristic of the remote service we are interested in.
static PROGMEM BLEUUID charUUID("6e400002-b5a3-f393-e0a9-e50e24dcca9e");
static boolean doConnect = false;
static boolean connected = false;
static boolean doScan = false;
static BLERemoteCharacteristic* pRemoteCharacteristic;
static BLEAdvertisedDevice* myDevice;
bool toggle1 = false;
class MyClientCallback : public BLEClientCallbacks {
void onConnect(BLEClient* pclient) {
}
void onDisconnect(BLEClient* pclient) {
connected = false;
doScan = true;
Serial.println("onDisconnect");
}
};
bool connectToServer() {
Serial.print("Forming a connection to ");
Serial.println(myDevice->getAddress().toString().c_str());
BLEClient* pClient = BLEDevice::createClient();
pClient->setClientCallbacks(new MyClientCallback());
// Connect to the remove BLE Server.
pClient->connect(myDevice); // if you pass BLEAdvertisedDevice instead of address, it will be recognized type of peer device address (public or private)
// Obtain a reference to the service we are after in the remote BLE server.
BLERemoteService* pRemoteService = pClient->getService(serviceUUID);
if (pRemoteService == nullptr) {
Serial.print("Failed to find our service UUID: ");
Serial.println(serviceUUID.toString().c_str());
pClient->disconnect();
return false;
}
// Obtain a reference to the characteristic in the service of the remote BLE server.
pRemoteCharacteristic = pRemoteService->getCharacteristic(charUUID);
if (pRemoteCharacteristic == nullptr) {
Serial.print("Failed to find our characteristic UUID: ");
Serial.println(charUUID.toString().c_str());
pClient->disconnect();
return false;
}
connected = true;
return true;
}
/**
* Scan for BLE servers and find the first one that advertises the service we are looking for.
*/
class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks {
/**
* Called for each advertising BLE server.
*/
void onResult(BLEAdvertisedDevice advertisedDevice) {
Serial.print("BLE Advertised Device found: ");
Serial.println(advertisedDevice.toString().c_str());
if (advertisedDevice.getName() == "MOONSIDE-T1") {
BLEDevice::getScan()->stop();
myDevice = new BLEAdvertisedDevice(advertisedDevice);
doConnect = true;
doScan = true;
}
// We have found a device, let us now see if it contains the service we are looking for.
if (advertisedDevice.haveServiceUUID() && advertisedDevice.isAdvertisingService(serviceUUID)) {
BLEDevice::getScan()->stop();
myDevice = new BLEAdvertisedDevice(advertisedDevice);
doConnect = true;
doScan = true;
} // Found our server
} // onResult
}; // MyAdvertisedDeviceCallbacks
void handleRoot() {
server.send(200, "text/plain", F("hello from esp32!"));
}
void handleOn() {
if (connected) {
String newValue = "LEDON";
pRemoteCharacteristic->writeValue(newValue.c_str(), newValue.length());
server.send(200, "text/plain", F("ok"));
} else {
server.send(200, "text/plain", F("not connected"));
}
}
void handleOff() {
if (connected) {
String newValue = "LEDOFF";
pRemoteCharacteristic->writeValue(newValue.c_str(), newValue.length());
server.send(200, "text/plain", F("ok"));
} else {
server.send(200, "text/plain", F("not connected"));
}
}
void handleBrightness() {
String rawVal = server.arg(0);
int val = rawVal.toInt();
if (val > 0 && val < 126) {
if (connected) {
String newValue = "BRIGH" + rawVal;
pRemoteCharacteristic->writeValue(newValue.c_str(), newValue.length());
server.send(200, "text/plain", F("ok"));
} else {
server.send(200, "text/plain", F("not connected"));
}
} else {
server.send(200, "text/plain", F("not in range"));
}
}
void handleColor() {
int r, g, b, bright = -1;
if (connected) {
for (int i = 0; i <= server.args(); i++) {
String currArgName = server.argName(i);
if (currArgName == "r" || currArgName == "red") {
r = server.arg(i).toInt();
}
if (currArgName == "g" || currArgName == "green") {
g = server.arg(i).toInt();
}
if (currArgName == "b" || currArgName == "blue") {
b = server.arg(i).toInt();
}
if (currArgName == "brigh" || currArgName == "brightness") {
bright = server.arg(i).toInt();
}
}
if (r >= 0 && r < 256 && g >= 0 && g < 256 && b >= 0 && b < 256) {
char colorString[15];
String brightAdditive = "";
sprintf(colorString, "COLOR%03d%03d%03d", r, g, b);
Serial.println(r);
// + + sprintf(newValue, "%03d", g) + sprintf("%03d", b);
if (bright != -1) {
// We have a brightness value
if (bright >= 0 && bright < 121) {
brightAdditive = " ";
brightAdditive += String(bright);
//newValue += " " + sprintf("%03d", bright);
//newValue += " 050";
;
} else {
server.send(200, "text/plain", F("not in range"));
}
}
pRemoteCharacteristic->writeValue((String(colorString) + brightAdditive).c_str(), (String(colorString) + brightAdditive).length());
server.send(200, "text/plain", "ok " + String(colorString));
} else {
server.send(200, "text/plain", F("not in range / missing argument"));
}
} else {
server.send(200, "text/plain", F("not connected"));
}
}
void setup() {
Serial.begin(115200);
Serial.println(F("Starting Arduino BLE Client application..."));
BLEDevice::init("");
// Retrieve a Scanner and set the callback we want to use to be informed when we
// have detected a new device. Specify that we want active scanning and start the
// scan to run for 5 seconds.
BLEScan* pBLEScan = BLEDevice::getScan();
pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
pBLEScan->setInterval(1349);
pBLEScan->setWindow(449);
pBLEScan->setActiveScan(true);
pBLEScan->start(5, false);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
WiFi.setHostname("esp32-ble-moonside");
WiFi.setAutoReconnect(true);
Serial.println("");
// Wait for connection
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(F("."));
}
Serial.println("");
Serial.print(F("IP address: "));
Serial.println(WiFi.localIP());
if (!MDNS.begin("esp32-ble-moonside")) {
Serial.println("Error setting up MDNS responder!");
} else {
Serial.println("mDNS responder started");
}
ArduinoOTA.setHostname("esp32-ble-moonside");
ArduinoOTA.setPassword("admin");
ArduinoOTA
.onStart([]() {
String type;
if (ArduinoOTA.getCommand() == U_FLASH)
type = "sketch";
else // U_SPIFFS
type = "filesystem";
// NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
Serial.println("Start updating " + type);
})
.onEnd([]() {
Serial.println("\nEnd");
})
.onProgress([](unsigned int progress, unsigned int total) {
Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
})
.onError([](ota_error_t error) {
Serial.printf("Error[%u]: ", error);
if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
else if (error == OTA_END_ERROR) Serial.println("End Failed");
});
ArduinoOTA.begin();
server.on("/", handleRoot);
server.on("/api/v1/ledon", handleOn);
server.on("/api/v1/ledoff", handleOff);
server.on("/api/v1/brightness", handleBrightness);
server.on("/api/v1/color", handleColor);
server.begin();
Serial.println(F("HTTP server started"));
} // End of setup.
// This is the Arduino main loop function.
void loop() {
server.handleClient();
ArduinoOTA.handle();
// If the flag "doConnect" is true then we have scanned for and found the desired
// BLE Server with which we wish to connect. Now we connect to it. Once we are
// connected we set the connected flag to be true.
if (doConnect == true) {
if (connectToServer()) {
Serial.println(F("We are now connected to the BLE Server."));
} else {
Serial.println(F("We have failed to connect to the server; there is nothin more we will do."));
}
doConnect = false;
}
// If we are connected to a peer BLE Server, update the characteristic each time we are reached
// with the current time since boot.
if (doScan) {
// BLEDevice::getScan()->start(0); // this is just example to start scan after disconnect, most likely there is better way to do it in arduino
}
delay(1000); // Delay a second between loops.
} // End of loop
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment