Skip to content

Instantly share code, notes, and snippets.

@philhartung
Forked from tjclement/LightCycle.ino
Last active January 7, 2025 17:07
Show Gist options
  • Save philhartung/6f196e49c2e8889c3bbf31b081bc6574 to your computer and use it in GitHub Desktop.
Save philhartung/6f196e49c2e8889c3bbf31b081bc6574 to your computer and use it in GitHub Desktop.
/*
* See documentation at https://nRF24.github.io/RF24
* See License information at root directory of this library
* Author: Brendan Doherty (2bndy5), Tom Clement (tjclement)
*/
/**
* A modified example from the NRF24 library, that enables control of levels of GL25B and many more Neweer light panels.
*/
#include <SPI.h>
#include "printf.h"
#include "RF24.h"
// Instantiate an object for the nRF24L01 transceiver.
// CE pin is wired to pin 15, CSN pin is wired to pin 17 on the Pi Pico.
RF24 radio(15, 17);
/*
Pi Pico Pinout:
nRF24 | Color | Pico Pin | Pico GPIO |
============================================
GND | black | 38 | N/A |
VCC (3.3V) | red | 36 | N/A |
CE | orange | 20 | 15 |
CSN | yellow | 22 | 17 |
SCK | green | 24 | 18 |
MOSI | violet | 25 | 19 |
MISO | blue | 21 | 16 |
*/
// Define the address used for TX/RX communication.
// In this use case, we only do transmissions.
uint8_t address[] = {0xD3, 0x5C, 0x6E};
// This struct represents the packet sent to the receiving device.
// It contains command bytes relevant to brightness and color temperature.
typedef struct {
uint8_t header;
uint8_t target_channel;
uint8_t unknown1;
uint8_t command_type; // e.g. 0x82 for brightness, 0x83 for color temperature
uint8_t command1; // main value (brightness or color temperature)
uint8_t command2; // offset value to accompany command1
uint8_t tail1;
uint8_t tail2;
uint8_t zeroes[24]; // not used, just padded with zero
} packet;
// Initialize the packet with default values.
packet payload = {
.header = 0x77,
.target_channel = 0x58,
.unknown1 = 0x01,
.command_type = 0x82, // default to brightness command
.command1 = 0x00,
.command2 = 0x52,
.tail1 = 0x00,
.tail2 = 0x00
};
// This buffer is used to print each byte of the payload in hexadecimal format.
char hexChar[3]; // 2 chars + null terminator
void setup() {
Serial.begin(115200);
while (!Serial) {
// Some boards need to wait to ensure access to serial over USB
}
// Initialize the transceiver on the SPI bus
if (!radio.begin()) {
Serial.println(F("Radio hardware is not responding!"));
while (1) {} // Hold in an infinite loop if radio is not found
}
// Set the power amplifier level
radio.setPALevel(RF24_PA_HIGH);
// We only send 32 bytes in each payload
radio.setPayloadSize(32);
// Configure other radio options
radio.setAutoAck(false);
radio.setAddressWidth(3);
radio.setChannel(10);
radio.setDataRate(RF24_250KBPS);
radio.setCRCLength(RF24_CRC_16);
// Open a writing pipe on the specified address.
// We only need pipe 0 for writing.
radio.openWritingPipe(address);
// We will not receive in this script, so stop listening.
radio.stopListening();
// For debugging info (optional):
// printf_begin();
// radio.printDetails();
// radio.printPrettyDetails();
Serial.println(F("=== Setup complete. Enter commands to adjust brightness or color temperature. ==="));
Serial.println(F("Usage: 'brightness <0-100>', 'color <29-70>' or 'power'"));
}
void loop() {
// Check if there is any serial input to parse
if (Serial.available()) {
// Read the entire line from the serial buffer
String input = Serial.readStringUntil('\n');
input.trim(); // Remove any leading/trailing whitespace
// If the user typed nothing, skip
if (input.length() == 0) return;
// Convert input to lowercase for easy comparison
String lowerInput = input;
lowerInput.toLowerCase();
// Parse commands
if (lowerInput.startsWith("brightness")) {
// Extract the numeric value after "brightness"
int value = parseValue(input, "brightness");
// Constrain brightness between 0 and 100 to avoid invalid values
value = constrain(value, 0, 100);
// Prepare the payload for brightness
payload.command_type = 0x82;
payload.command1 = value;
// The second byte for brightness uses offset 0x52
payload.command2 = 0x52 + value;
// Transmit the packet
transmitPacket();
} else if (lowerInput.startsWith("color")) {
// Extract the numeric value after "color"
int value = parseValue(input, "color");
// Constrain color temperature between 29 and 70
value = constrain(value, 29, 70);
// Prepare the payload for color temperature
payload.command_type = 0x83;
payload.command1 = value;
// The second byte for color uses offset 0xBA
payload.command2 = 0xBA + value;
// Transmit the packet
transmitPacket();
} else if (lowerInput.startsWith("power")) {
payload.command_type = 0x85;
payload.command1 = 0x01;
payload.command2 = 0x00;
transmitPacket();
} else {
// Unrecognized command
Serial.println(F("Unknown command. Valid commands: 'brightness <0-100>', 'color <29-70>' or 'power'."));
}
}
}
/**
* Helper function to parse the numeric value from a command like:
* "brightness 50" or "color 32".
* It returns -1 if the parse fails.
*/
int parseValue(const String &input, const String &command) {
// Erstelle eine lokale Kopie von 'input'
String tmp = input;
// Wandelt die Kopie in Kleinbuchstaben um
tmp.toLowerCase();
// Nun kann man 'indexOf(command)' gefahrlos aufrufen
int index = tmp.indexOf(command);
if (index == -1) {
return -1;
}
// Extrahiere den Teil nach 'command'
String numericPart = tmp.substring(index + command.length());
numericPart.trim();
// Wandle den extrahierten Teil in eine Zahl um
return numericPart.toInt();
}
/**
* Transmits the current payload packet via the nRF24 radio and prints info to Serial.
*/
void transmitPacket() {
// Start timer for diagnostics
unsigned long startTimer = micros();
// Perform the write operation
bool report = radio.write(&payload, sizeof(payload));
// End timer
unsigned long endTimer = micros();
// Print the entire payload in hex
uint8_t* castPayload = (uint8_t*) &payload;
for(int i = 0; i < sizeof(payload); i++) {
sprintf(hexChar, "%02X", castPayload[i]);
Serial.print(hexChar);
}
Serial.println();
// Check if the transmission was successful
if (report) {
Serial.print(F("Transmission successful! Time to transmit = "));
Serial.print(endTimer - startTimer);
Serial.println(F(" us."));
} else {
Serial.println(F("Transmission failed or timed out."));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment