EDIT: Big misunderstanding on my part. Data has to go the other way! From Peripheral to Central. IE: the trunk with lights has to be Central, the bike sending the signals is Peripheral. Works much better now, ignore all the nonsense below.
The intent of this project is to read turn and brake signals on a motorcycle via one Nano IOT (Central), and pass the data to LED light strips on luggage that has 12v power available (via a second Nano IOT - Peripheral). Lights normally are in one of 2 possible states: DIM or BRIGHT (added OFF for debugging). I'm trying to send the data as an aggregate byte with a value between 0 and 9 to represent the various possible combinations of DIM / BRIGHT. Default is DIM on both sides (ie: tail lights).
The two Nanos do find each other and connect OK (I borrowed heavily from the examples), both according to the serial monitor and some code I inserted that blinks the lights only if the connection is made.
Problem: lights come on DIM both sides and stay there regardless of signal/brake status. I think I've narrowed it down to the data not being written or understood at the peripheral. I'm stuck as to why. I would greatly appreciate any assistance.
I have commented the code, including the portions inserted for debugging in the peripheral sketch and what sections seem to execute. But right now as shown, I get the 10 alternating BRIGHT/OFF followed by a single DIM before repeating.
This is the Control (bike end) sketch:
/*
GIVI Brake/Turn Control - central (on bike)
This sketch scans for a BLE peripheral until one with the advertised service
"53EB1DAB-329C-41D1-B257-0567183D5913" UUID is found. Once discovered and connected,
it will remotely control the peripheral's two outputs to the LED strips, based on inputs from the brake and turn signals.
The circuit:
- Arduino MKR WiFi 1010, Arduino Uno WiFi Rev2 board, Arduino Nano 33 IoT,
Arduino Nano 33 BLE, or Arduino Nano 33 BLE Sense board.
- two three-terminal 3.3v regulators and associated capacitors
You can use it with another board that is compatible with this library and the
companion givi_lights_perephrial sketch.
*/
#include <ArduinoBLE.h>
// constants for inputs
const byte brakePin = 9;
const byte rtPin = 5;
const byte ltPin = 2;
// constant for flasher duration timers
const unsigned long flashInterval = 1600;
// variables used for calculations
byte LTSTATUS = 0;
byte RTSTATUS = 0;
byte BRSTATUS = 0;
byte STATUS = 0;
byte TIMERRT = 0;
byte TIMERLT = 0;
void setup() {
Serial.begin(9600);
// while (!Serial);
// configure input pins
pinMode(brakePin, INPUT);
pinMode(rtPin, INPUT);
pinMode(ltPin, INPUT);
// initialize the Bluetooth® Low Energy hardware
BLE.begin();
Serial.println("Bluetooth® Low Energy Central - givi lights control bike end");
// start scanning for peripherals
BLE.scanForUuid("53EB1DAB-329C-41D1-B257-0567183D5913");
}
void loop() {
// check if a peripheral has been discovered
BLEDevice peripheral = BLE.available();
if (peripheral) {
// discovered a peripheral, print out address, local name, and advertised service
Serial.print("Found ");
Serial.print(peripheral.address());
Serial.print(" '");
Serial.print(peripheral.localName());
Serial.print("' ");
Serial.print(peripheral.advertisedServiceUuid());
Serial.println();
if (peripheral.localName() != "TRUNK") {
return;
}
// stop scanning
BLE.stopScan();
controlLed(peripheral);
// peripheral disconnected, start scanning again
BLE.scanForUuid("53EB1DAB-329C-41D1-B257-0567183D5913");
}
}
void controlLed(BLEDevice peripheral) {
// connect to the peripheral
Serial.println("Connecting ...");
if (peripheral.connect()) {
Serial.println("Connected");
} else {
Serial.println("Failed to connect!");
return;
}
// discover peripheral attributes
Serial.println("Discovering attributes ...");
if (peripheral.discoverAttributes()) {
Serial.println("Attributes discovered");
} else {
Serial.println("Attribute discovery failed!");
peripheral.disconnect();
return;
}
// retrieve the LED characteristic
BLECharacteristic ledCharacteristic = peripheral.characteristic("19b10001-e8f2-537e-4f6c-d104768a1215");
if (!ledCharacteristic) {
Serial.println("Peripheral does not have LED characteristic!");
peripheral.disconnect();
return;
} else if (!ledCharacteristic.canWrite()) {
Serial.println("Peripheral does not have a writable LED characteristic!");
peripheral.disconnect();
return;
}
unsigned long elapsedRT = 0;
unsigned long elapsedLT = 0;
unsigned long startLT = 0;
unsigned long startRT = 0;
while (peripheral.connected()) {
// while the peripheral is connected
// LT is left turn input, RT is right turn input, BR is brake input.
// LTSTATUS, etc. is the calculated status of the left turn signal, etc.
// STATUS is the sum total and final output to the second Nano IOT.
// Status values are such that the final STATUS value must be unique for each condition.
// brake light is easy, it's either on or off
if (brakePin == HIGH)
{
BRSTATUS = 1;
} else {
BRSTATUS = 0;
}
// because the bike has separate turn and brake lights,
// I need to allow time to determine if the signal has been turned off or is just between flashes
if (ltPin == HIGH && TIMERLT == 0);
{
// code to start left turn signal timer if not running yet when signal goes active.
if (TIMERLT == 0)
{
startLT = millis();
}
}
// check to see if the elapsed time has exceeded the flash interval. If it has, return 0, if it hasn't return 1
elapsedLT = millis() - startLT;
if (elapsedLT >= flashInterval)
{
TIMERLT = 0;
} else {
TIMERLT = 1;
}
// set LTSTATUS to 2 if flash is active or 4 if flash is inactive but timer running
if (ltPin == HIGH)
{
LTSTATUS = 2;
if (ltPin == LOW && TIMERLT == 1)
{
LTSTATUS = 4;
}
// if timer has expired and left signal is inactive, set LTSTATUS to 0
} else {
LTSTATUS = 0;
}
// similar for the right turn signal
if (rtPin == HIGH && TIMERRT == 0);
{
// code to start right turn signal timer if not running yet when signal goes active.
if (TIMERRT == 0)
{
startRT = millis();
}
}
// check to see if the elapsed time has exceeded the flash interval. If it has, return 0, if it hasn't return 1
elapsedRT = millis() - startRT;
if (elapsedRT >= flashInterval)
{
TIMERRT = 0;
} else {
TIMERRT = 1;
}
// set RTSTATUS to 6 if flash is active or 8 if flash is inactive but timer running
if (rtPin == HIGH)
{
RTSTATUS = 6;
if (ltPin == LOW && TIMERLT == 1)
{
RTSTATUS = 8;
}
// if timer has expired and right signal is inactive, set RTSTATUS to 0
} else {
RTSTATUS = 0;
}
// sum of all status codes
STATUS = (BRSTATUS + LTSTATUS + RTSTATUS);
// special case to handle 4-way flashers
if (LTSTATUS == 2 && RTSTATUS == 6)
{
STATUS = 1;
}
if (LTSTATUS == 4 && RTSTATUS == 8)
{
STATUS = 0;
}
ledCharacteristic.writeValue(STATUS);
}
Serial.println("Peripheral disconnected");
}
And here is the luggage (lighting) end sketch:
/*
Givi brake/turn lights control -- perepherial (Trunk box)
When paired with a second device running the associated central service this sketch is used
to control the lights on a Givi trunk box.
The circuit:
- Arduino Nano 33 IoT,
- Use MOSFETS to isolate 3.3 volt outputs from nominal 12v supply. Pin 9 = left side, Pin 3 = right side
- 3.3Kohm 1/8watt resistor between gate and source -- bleeds voltage from gate when pin is low
- 100ohm 1/8 watt resistor between gate and pin -- proteccts port from possible surge
*/
#include <ArduinoBLE.h>
BLEService ledService("53EB1DAB-329C-41D1-B257-0567183D5913"); // Bluetooth® Low Energy LED Service
// Bluetooth® Low Energy LED Switch Characteristic - custom 128-bit UUID, read and writable by central
BLEByteCharacteristic switchCharacteristic("19B10001-E8F2-537E-4F6C-D104768A1215", BLERead | BLEWrite);
const byte leftPin = 9; // controls left LED strip
const byte rightPin = 3; // controls right LED strip
byte STATUS = 0; // initial state on boot will be tail lights only
int DIM = 75; // tail light brightness
int BRIGHT = 255; // brake-turn brightness
int OFF = 0; // debug state
void setup() {
Serial.begin(9600);
// while (!Serial);
// set LED pin to output mode
pinMode(leftPin, OUTPUT);
pinMode(rightPin, OUTPUT);
analogWrite(leftPin, DIM); // turn on tail light on boot
analogWrite(rightPin, DIM); // turn on right tail light on boot
// begin initialization
if (!BLE.begin()) {
Serial.println("starting Bluetooth® Low Energy module failed!");
while (1);
}
// set advertised local name and service UUID:
BLE.setLocalName("TRUNK");
BLE.setAdvertisedService(ledService);
// add the characteristic to the service
ledService.addCharacteristic(switchCharacteristic);
// add service
BLE.addService(ledService);
// set the initial value for the characeristic:
switchCharacteristic.writeValue(0);
// start advertising
BLE.advertise();
Serial.println("BLE LED Peripheral - lights end");
}
void loop() {
// listen for Bluetooth® Low Energy peripherals to connect:
BLEDevice central = BLE.central();
// if a central is connected to peripheral:
if (central) {
Serial.print("Connected to central: ");
// print the central's MAC address:
Serial.println(central.address());
// debug code to verify connection without serial print available.
// Alternately flashes the lights from off to full 10 times.
for (int i = 0; i <= 10; i++) {
analogWrite(leftPin, BRIGHT);
analogWrite(rightPin, OFF);
delay(250);
analogWrite(leftPin, OFF);
analogWrite(rightPin, BRIGHT);
delay(250);
}
analogWrite(leftPin, OFF); // mark end of sequence to see if it is looping
analogWrite(rightPin, OFF);
delay(250);
// end of debug code -- NOTE: program gets this far.
// while the central is still connected to peripheral:
while(central.connected()) {
// debug code to verify the while condition is true
analogWrite(leftPin, DIM); // return lights to tail light mode.
analogWrite(rightPin, DIM); // note: program gets this far, then returns to the debug code above in a continuous loop.
// if the remote device wrote to the characteristic,
// use the value to control the lights:
// debug code to see if the characteristic is written: NOTE: this code is never executed
// seemingly indicating something WAS written.
if (!switchCharacteristic.written()) { // if nothing was written
for (int i = 0; i <= 10; i++) {
analogWrite(leftPin, BRIGHT);
analogWrite(rightPin, BRIGHT);
delay(100);
analogWrite(leftPin, DIM);
analogWrite(rightPin, DIM);
delay(100);
}
// end debug code
}
if (switchCharacteristic.written()) { // if something was written
// debug code to verify a characteristic was written. NOTE: this code never executes
// seemingly indicating samthing was NOT written. How can both be true?
delay(250);
for (int i = 0; i <= 10; i++) {
analogWrite(leftPin, OFF);
analogWrite(rightPin, OFF);
delay(150);
analogWrite(leftPin, DIM);
analogWrite(rightPin, DIM);
delay(150);
}
// end of debug code
STATUS = switchCharacteristic.value();
// normal running, no brakes or turn, just tail. Use PWM to dim both sides
if (STATUS == 0)
{
analogWrite(leftPin, DIM);
analogWrite(rightPin, DIM);
}
// brakes, no turn. Both sides on full output
if (STATUS == 1)
{
analogWrite(leftPin, BRIGHT);
analogWrite(rightPin, BRIGHT);
}
// left turn illuminated, no brakes. left side on full, right at tail level
if (STATUS == 2)
{
analogWrite(leftPin, BRIGHT);
analogWrite(rightPin, DIM);
}
// left turn illuminated, brakes on. Both sides on full
if (STATUS == 3)
{
analogWrite(leftPin, BRIGHT);
analogWrite(rightPin, BRIGHT);
}
// left turn on dim part of flash sequence, no brakes. Both sides at tail level.
if (STATUS == 4)
{
analogWrite(leftPin, DIM);
analogWrite(rightPin, DIM);
}
// left turn on dim part of flash sequence, brakes on. Left side dim, right side on full.
if (STATUS == 5)
{
analogWrite(leftPin, DIM);
analogWrite(rightPin, BRIGHT);
}
// right turn illuminated, no brakes
if (STATUS == 6)
{
analogWrite(leftPin, DIM);
analogWrite(rightPin, BRIGHT);
}
// right turn illuminated, brakes on
if (STATUS == 7)
{
analogWrite(leftPin, BRIGHT);
analogWrite(rightPin, BRIGHT);
}
// right turn on dim part of flash sequence, brakes off
if (STATUS == 8)
{
analogWrite(leftPin, DIM);
analogWrite(rightPin, DIM);
}
// right turn on dim part of flash sequence, brakes on
if (STATUS == 9)
{
analogWrite(leftPin, DIM);
analogWrite(rightPin, BRIGHT);
}
}
}
analogWrite(leftPin, DIM); // Revert to tail light as default on loss of connection
analogWrite(rightPin, DIM); // Revert to tail light as default on loss of connection
}
}