Created
December 16, 2024 05:17
-
-
Save kylemanna/d3e88fda7e4cf963cab3f471a532eda7 to your computer and use it in GitHub Desktop.
Shelly Plus RGBW Arduino BLE Server
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import asyncio | |
import argparse | |
import sys | |
from bleak import BleakClient | |
# Updated characteristic UUID | |
characteristic_uuid = "1ED5100D-F00D-FA11-0F1C-1ED5100D1F10" | |
def parse_args(): | |
parser = argparse.ArgumentParser(description="Read and optionally write PWM values to an ESP32 BLE device.") | |
parser.add_argument("mac", help="The MAC address of the ESP32 BLE device") | |
parser.add_argument("pwm_values", nargs="*", help="Four hex values (e.g. 0x11 0x22 0x33 0x44) for PWM channels") | |
return parser.parse_args() | |
async def main(): | |
args = parse_args() | |
# Validate PWM values if provided | |
pwm_values = None | |
if len(args.pwm_values) > 0: | |
if len(args.pwm_values) != 4: | |
print("You must provide exactly 4 PWM values or none at all.") | |
sys.exit(1) | |
try: | |
pwm_values = [int(val, 16) for val in args.pwm_values] | |
except ValueError: | |
print("Invalid PWM values. Use hex format like 0x11 0x22 0x33 0x44.") | |
sys.exit(1) | |
esp32_address = args.mac | |
async with BleakClient(esp32_address) as client: | |
connected = client.is_connected | |
print(f"Connected to {esp32_address}: {connected}") | |
# Read the current value of the characteristic | |
current_value = await client.read_gatt_char(characteristic_uuid) | |
# Print the current value in hex format (similar to input style) | |
hex_output = " ".join([f"0x{b:02X}" for b in current_value]) | |
print("Current Value (hex):", hex_output) | |
# If PWM values are provided, write them to the device | |
if pwm_values is not None: | |
await client.write_gatt_char(characteristic_uuid, bytes(pwm_values)) | |
print(f"Wrote PWM values {['0x{:02X}'.format(v) for v in pwm_values]} to the ESP32") | |
asyncio.run(main()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <Arduino.h> | |
#include <driver/ledc.h> | |
#include <BLEDevice.h> | |
#include <BLEServer.h> | |
#include <BLEUtils.h> | |
#include <BLE2902.h> | |
// BLE UUIDs | |
#define SERVICE_UUID "C0FFEE00-FACE-FADE-DEAD-C0FFEEDECADE" | |
#define CHARACTERISTIC_UUID "1ED5100D-F00D-FA11-0F1C-1ED5100D1F10" | |
// Pin definitions for LEDs (e.g., RGBW) | |
#define LEDC_OUTPUT_PIN_0 25 // Red LED pin | |
#define LEDC_OUTPUT_PIN_1 26 // Green LED pin | |
#define LEDC_OUTPUT_PIN_2 27 // Blue LED pin | |
#define LEDC_OUTPUT_PIN_3 4 // White LED pin | |
static uint8_t pwmValues[4] = {0x01, 0x01, 0x01, 0x01}; | |
// Callback to handle writes to the characteristic | |
class MyCharacteristicCallbacks : public BLECharacteristicCallbacks { | |
void onWrite(BLECharacteristic *pCharacteristic) { | |
// getValue() returns a String | |
String value = pCharacteristic->getValue(); | |
if (value.length() == 4) { | |
// Expecting 4 bytes of data | |
pwmValues[0] = (uint8_t)value[0]; | |
pwmValues[1] = (uint8_t)value[1]; | |
pwmValues[2] = (uint8_t)value[2]; | |
pwmValues[3] = (uint8_t)value[3]; | |
Serial.printf("Received PWM Values: %d, %d, %d, %d\n", | |
pwmValues[0], pwmValues[1], pwmValues[2], pwmValues[3]); | |
// Update the LEDC duty cycle based on new values | |
ledcWrite(LEDC_OUTPUT_PIN_0, pwmValues[0]); | |
ledcWrite(LEDC_OUTPUT_PIN_1, pwmValues[1]); | |
ledcWrite(LEDC_OUTPUT_PIN_2, pwmValues[2]); | |
ledcWrite(LEDC_OUTPUT_PIN_3, pwmValues[3]); | |
} else { | |
Serial.println("Invalid data length, expected 4 bytes."); | |
} | |
} | |
}; | |
// Callback to handle connect/disconnect events on the server | |
class MyServerCallbacks : public BLEServerCallbacks { | |
void onConnect(BLEServer* pServer) { | |
Serial.println("Client connected"); | |
} | |
void onDisconnect(BLEServer* pServer) { | |
Serial.println("Client disconnected"); | |
// Restart advertising so the client can reconnect | |
BLEDevice::startAdvertising(); | |
Serial.println("Advertising restarted"); | |
} | |
}; | |
void setup() { | |
Serial.begin(115200); | |
Serial.println("Starting BLE server..."); | |
// Assign LEDC channels automatically | |
// ledcAttach(pin, frequency, resolution_bits) | |
ledcAttach(LEDC_OUTPUT_PIN_0, 5000, 8); | |
ledcAttach(LEDC_OUTPUT_PIN_1, 5000, 8); | |
ledcAttach(LEDC_OUTPUT_PIN_2, 5000, 8); | |
ledcAttach(LEDC_OUTPUT_PIN_3, 5000, 8); | |
// Set initial duty cycles (all off) | |
ledcWrite(LEDC_OUTPUT_PIN_0, pwmValues[0]); | |
ledcWrite(LEDC_OUTPUT_PIN_1, pwmValues[1]); | |
ledcWrite(LEDC_OUTPUT_PIN_2, pwmValues[2]); | |
ledcWrite(LEDC_OUTPUT_PIN_3, pwmValues[3]); | |
// Initialize BLE | |
BLEDevice::init("ESP32-PWM-LED"); | |
BLEServer *pServer = BLEDevice::createServer(); | |
pServer->setCallbacks(new MyServerCallbacks()); | |
// Create BLE Service | |
BLEService *pService = pServer->createService(SERVICE_UUID); | |
// Create a BLE Characteristic | |
BLECharacteristic *pCharacteristic = pService->createCharacteristic( | |
CHARACTERISTIC_UUID, | |
BLECharacteristic::PROPERTY_READ | | |
BLECharacteristic::PROPERTY_WRITE | |
); | |
pCharacteristic->setCallbacks(new MyCharacteristicCallbacks()); | |
pCharacteristic->addDescriptor(new BLE2902()); | |
pCharacteristic->setValue(pwmValues, 4); | |
// Start the service | |
pService->start(); | |
// Start advertising | |
BLEAdvertising *pAdvertising = BLEDevice::getAdvertising(); | |
pAdvertising->addServiceUUID(SERVICE_UUID); | |
pAdvertising->setScanResponse(true); | |
pAdvertising->setMinPreferred(0x06); | |
pAdvertising->setMaxPreferred(0x12); | |
BLEDevice::startAdvertising(); | |
Serial.println("BLE server is running and advertising."); | |
} | |
void loop() { | |
delay(1000); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment