Bluetooth Re-transmitter Transmitter Sketch

Definitions and Declarations

/*  Bluetooth reTransmitter beige box with red antenna.

    Uses a Picaxe 08M2 to receive broadcast messages in the 330 MHz  band..

    This communicates via I2C to an Arduino nano 33 BLE.

    This stores all ov the data and transmits thi data set formatted via Bluetooth.

   John Saunders 5/13/2025

*/

#include <Wire.h> //I2C library

#include <ArduinoBLE.h>

#define I2Caddr 0x07

#define fldLenMax 7

#define msgNum 6

#define fldsNum 24

#define sync   A6

#define blueLED  8

#define greenLED 9

#define btTxd 12

#define btRxd A0

#define btEn A1

#define btState 13

#define buffLen 24

#define cmdsNum 26

#define dispSelNum 19

#define BLEOffset 400


// ------------------------- Data structons for messages ------------------


struct msg_t {

  char keyCode;

  uint8_t fldQty;

  uint8_t period;        // in seconds

  char timestamp[6];    //hh:mm

};


msg_t msgs[msgNum] = {

  {'t', 4, 62, "10:23"},  {'s', 4, 74,  "10:23"},  {'r', 4, 74, "10:23"},  {'n', 3, 153, "10:23"},

  {'z', 2, 153, "10:23"},  {'u', 4, 255, "10:23"}

};


struct fld_t {

  char fldData[fldLenMax];

  uint8_t len;

  uint8_t areaInx;

  uint8_t typeInx;

  uint8_t unitsInx;

  byte dp;       //Decimal Point: 0 = none, 1 = after 1 digit , 2 = after 2 digits, etc

};


const String titles[] = {

  " ",     ":",     "/",     "%",     "MA",     "V",    "`F", "inHg",    "MAH",     "Kohm",                    //  0 -  9

  "p", "own", "door is ", "fan is ",  "ot", "unning", "topped", "Outside ", "Garage ", "Air Quality ",          // 10 - 19

  "Inside ", "Temperature = ", "Humidity = ", "Solar ", "Current = ", "Battery = ", "Barometric Pressure = ",    // 20 - 26                                       // 20 - 24

  "Charging = ", "Previous = ", "level = ", "High = ", "Low = ", "Light = ", "\n",  "          ",            // 27 - 34

  "Daily = ",  ",\t", "29.", "30.", "Status", "Network", "is", "ool", "Environment", " ----------- "          // 35 - 44

};


fld_t flds[fldsNum] = {

  //t          Month             Date                         Hour                Minute                        // 0 - 3

  {"11", 2, 100, 255, 2, 0}, {"06", 2, 100, 255, 0, 0}, {"19", 2, 100, 255, 1, 0}, {"07", 2, 100, 255, 255, 0},

  //s Outside Temperature      Humidity             Solar Current         Battery Voltage                       // 4 - 7

  {"063", 3, 17, 21, 6, 0}, {"064", 3, 17, 22, 3, 0}, {"001", 3 , 23, 24, 4, 0}, {"538", 4, 17, 25, 5, 1},

  //r Barometric Pressure    Charging Voltage     Current charge for day    Yesterday's charge                  // 8 - 11

  {"006", 3, 26, 37, 7, 0}, {"049", 4, 23, 27, 5, 2}, {"0369", 4, 23, 35, 8, 0}, {"0402", 4, 23, 28, 8, 0},

  //n Air Quality Alarm           High Reading               Low Reading                     ageing & last     // 12 - 15

  {"A", 1, 19, 29, 255, 0}, {"09.847", 6, 19, 31, 9, 0}, {"09.066", 6, 19, 30, 9,  0}, {" ", 1, 255, 255, 255, 0},

  //z   Inside Temperature          Inside Light                 begin heading               end heading       // 16 - 19

  {"0087.8", 6, 20, 21, 6, 0}, {"00265", 5, 20, 32, 255,  0}, {" ", 1, 255, 255, 34, 0}, {" ", 1, 34, 255, 255, 0},

  //u Garage Temperature    Garage Door Status    Garage temp Status    Garage Fan Status                       // 20 - 23

  {"078", 3, 18, 21, 6, 0}, {"D", 1, 18, 12, 10, 0}, {"H", 1, 18, 21, 14, 0}, {"S", 1, 18, 13, 15, 0}

};


const int outputs[] = {

  133, 144, 143, 144, 133, 4, 136, 16, 133, 8, 136, 5, 133, 17, 136, 20, 133,  13, 136, 14, 133,

  144, 139, 144, 133, 21, 133, 22, 136, 23, 133, 6, 136, 9, 133, 10, 136, 11, 133, 7, 133,

  200, 201, 202, 204, 205, 133, -2

};


/* --------------------- command and display message display headers ------------

  const String items[] = {

  "Reading Lamp",     "Pinapple lights", "Shelf Lights",      "Ceiling Light",        "Bluetooth Speaker",

  "Hanging Lamp",     "Eggs Display",    "Flashing Display",  "Missions Illumination", "Eves LED String",

  "Gazebo LED String", "Gazebo Top Light", "Owl Fountain",      "Cherub Fountain",      "Pole Lamp",

  "Flower Control"

  };

  const String acts[] = {"OFF", "ON"};


  // --------------------- Data structures for display selections ------------

  // "Living Room Lights", "Ornaments", "Garden Lights", "House Lights", "Cube Alarm", "Atmosphere", "Color LED Display", "Tower Display"


  const String hdrText[] = {

  "Living Room Lights", "Ornaments", "Garden Lights", "House Lights", "Cube Alarm", "Atmosphere", "Color LED Display", "Tower Display"

  };



  // ------------------------- Data structures for commands ------------------

  struct comnd_t {

  char onCode;

  char offCode;

  String cmdName;

  };


  const comnd_t cmds[cmdsNum]  = {

  {'1', '0', "Owl Fountain"}, {'3', '2', "Cherub Fountain"}, {'5', '4', "Gazebo String Lights"}, {'K', '8', "Pineapple Lights"},

  {'d', '9', "Circle Ornaments"}, {'d', '9', "Clear Box Ring"}, {'a', 'c', "Flower Receiver"}, {'I', 'C', "Hanging Macrame Lamp"},

  {'b', 'f', "Reading Lamp"}, {'E', 'F', "Wall unit shelves"}, {'M', 'g', "Missions Lights"}, {'M', 'g', "Missions Models Lights"},

  {'R', 'G', "Ceiling Lamp"}, {'G', 'R', "Gazebo Top Light"}, {'A', 'H', "Cube Alarm Red LED"}, {'B', 'H', "Cube Alarm Play BaBa"},

  {'D', 'H', "Cube Alarm Green LED"}, {'e', 'H', "Cube Alarm Blue LED"}, {'Q', 'H', "Cube Alarm Play Chime"}, {'m', 'J', "Eves String Lights"},

  {'i', 'k', "Yard Pole Lamp"}, {'L', 'V', "Gazebo 28V Socket"}, {'U', 'S', "Bluetooth Speaker"}, {'Y', 'W', "Flashing Ornaments"},

  {'N', 'X', "Clear Box Tip"}, {'h', 'H', "Cube Alarm Play Siren"}

  };


  // ------------------- Data structons for display selection -----------------

  struct disp_t {

  char    selCode;

  uint8_t itemInx;      // index into itemLocs

  String    selName;

  };


  const char *locs[3] = {"Color LED", "Big Dial", "Red LED"};


  const disp_t disps[dispSelNum] = {

  { 'A', 0, "Garage Door & Fan"}, {'B', 0, "Sensor Battery"}, {'C', 0, "Temperatures"},     {'D', 0, "Humidities"},

  {'E', 0, "Barometer & Solar"},  {'F', 0, "Night Time"},     {'a', 1, "Room Temperature"}, {'b', 1, "Room Humidity"},

  { 'c', 1, "External Temperature"}, {'d', 1, "External Humidity"}, {'e', 1, "Solar Current"}, {'f', 1, "Barometer"},

  { 'g', 1, "Gas Quality"}, {'K', 2, "Date"}, {'L', '2', "Time"}, {'M', 2, "Temperature"},

  { 'N', 2, "Humidity"}, {'O', 2, "Solar Current"}, {'P', 2, "Battery Voltage"}

  };


*/

// ----------------------------- Global variables -------------------------


bool newMsgFlag;

bool isClock;

bool serOn;

bool advert;

char cmdChar;

char dispChar;

int  msgInx;


// ------------------------- BLE service ------------------------------------

BLEService               JohnsService("19B10000-E8F2-537E-4F6C-D104768A1214"); // Custom BLE service

BLECharacteristic eventCharacteristic("19B10001-E8F2-537E-4F6C-D104768A1214", BLERead | BLEWrite, 3);

BLECharacteristic  dataCharacteristic("19B10002-E8F2-537E-4F6C-D104768A1214", BLERead | BLENotify, 33);

Setup and Loop

void setup() {

  pinMode(greenLED, OUTPUT);

  pinMode(blueLED, OUTPUT);

  pinMode(sync, INPUT);

  pinMode(A4, INPUT);

  pinMode(A5, INPUT);

  pinMode(btRxd, OUTPUT);

  pinMode(btEn, OUTPUT);

  pinMode(btTxd, INPUT);

  pinMode(btState, INPUT);

  digitalWrite(btEn, LOW);

  digitalWrite(blueLED, LOW);

  digitalWrite(greenLED, LOW);

   Serial.begin(9600);

  delay(1000);

  Serial.println("Welcome to Nano33BLE");

  if (!Serial) {

    serOn = false;

  }

  Wire.begin(I2Caddr);

  Wire.onReceive(receiveEvent);

  serOn = true;

  attachInterrupt(digitalPinToInterrupt(sync), gotRcvrMsg, RISING);

 

  // BLE initialization

  if (!BLE.begin() && serOn) {

    Serial.println("Failed to start BLE!");

  }

  if (serOn) {

    Serial.println("BME initialized");

  }

  BLE.setLocalName("Nano33BLE");

  BLE.setAdvertisedService(JohnsService);

  JohnsService.addCharacteristic(eventCharacteristic);

  JohnsService.addCharacteristic(dataCharacteristic);

  BLE.addService(JohnsService);

  BLE.setAdvertisingInterval(325);

  BLE.setTimeout(3000000);

  BLE.advertise();

  newMsgFlag = false;

  delay(10);

}


void loop() {

  if (advert) {

    advert = false;

    BLE.advertise();

  }

  BLEDevice central = BLE.central();

  if (central) {

    digitalWrite(greenLED, HIGH);

    while (central.connected()) {

      if (newMsgFlag) {

        editPressure();

        editGarageDoor();

        editGarageTemp();

        editGarageFan();

        editAgeing();

        newMsgFlag = false;

      }

      if (eventCharacteristic.written() || isClock) {

        if (eventCharacteristic.value()) {   // any value other than 0

          digitalWrite(blueLED, HIGH);

          sendData();

          digitalWrite(blueLED, LOW);

        }

        isClock = false;

      }

      delay(80);

    }

  }

  else {

    delay(1000);

  }



  digitalWrite(greenLED, LOW);

}

// ------------------------- Utilities ------------------------------------


byte getMsgInx(char code) {

  int inx =  0;

  for (inx = 0; inx < msgNum; inx++) {

    if (msgs[inx].keyCode == code) break;

  }

  return (inx);

}

/*

  int getCmdInx(char keyCode) {

  int retVal  = -1;

  for (int inx = 0; inx < cmdsNum; inx++) {

    if (cmds[inx].onCode == keyCode) {

      retVal = inx;

      break;

    }

    if (cmds[inx].offCode == keyCode) {

      retVal = inx + 100;

      break;

    }

  }

  return retVal;

  }


  int getDispInx(char keyCode) {

  int retVal  = -1;

  for (int inx = 0; inx < dispSelNum; inx++) {

    if (disps[inx].selCode == keyCode) {

      retVal = inx;

      break;

    }

  }

  return retVal;


  }

*/

void editPressure(void) {

  if (flds[8].fldData[0] > 53) {

    flds[8].typeInx = 37;

  }

  else {

    flds[8].typeInx = 38;

  }

}


void editGarageDoor(void) {

  if (flds[21].fldData[0] == 68) {

    flds[21].unitsInx = 11;

  }

  else {

    flds[21].unitsInx = 10;

  }

}


void editGarageTemp(void) {

  if (flds[22].fldData[0] == 67) {

    flds[22].unitsInx = 42;

  }

  else {

    flds[22].unitsInx = 14;

  }

}


void editGarageFan(void) {

  if (flds[23].fldData[0] == 84) {

    flds[23].unitsInx = 15;

  }

  else {

    flds[23].unitsInx = 16;

  }

}

void editAgeing(void) {

  msgs[msgInx].timestamp[0] = flds[2].fldData[0];

  msgs[msgInx].timestamp[1] = flds[2].fldData[1];

  msgs[msgInx].timestamp[2] = ':';

  msgs[msgInx].timestamp[3] = flds[3].fldData[0];

  msgs[msgInx].timestamp[4] = flds[3].fldData[1];

  msgs[msgInx].timestamp[5] = 0;

}

// ------------------------- Communications ------------------

void gotRcvrMsg(void) {

  //digitalWrite(blueLED, HIGH);

  advert = true;

}


int num_byte;


void receiveEvent(int rty) {

  char picChar;

  char selChar = '[';

  int rxCount = -1;

  byte fldInx;

  byte fldCnt;

  byte stoInx;

  digitalWrite(blueLED, LOW);

  while (Wire.available() > 0)  {

    picChar = Wire.read();

    if (picChar == '>') {

      newMsgFlag = true;

    }

    if (picChar == '<') {

      rxCount = 0;

    }

    if (rxCount < 0) {

      newMsgFlag = false;

    }

    if (rxCount == 2) {

      selChar = picChar;

      msgInx = getMsgInx(selChar);

      if (msgInx < msgNum) {

        msgs[msgInx].keyCode = selChar;

      }

      if (selChar == 't') {

        isClock = true;

      }

      fldCnt = 0;

      stoInx = 0;

    }

    if ((rxCount > 3 ) && (msgInx < msgNum)) {

      fldInx = (4 * msgInx) + fldCnt;

      if ((stoInx == flds[fldInx].dp) && (flds[fldInx].dp > 0)) {

        flds[fldInx].fldData[stoInx++] = '.';

      }

      if ((picChar > 44)  && (stoInx < flds[fldInx].len)) {

        flds[fldInx].fldData[stoInx++] = picChar;

      }

      if (picChar == 44) {

        fldCnt++;

        stoInx = 0;

      }

    }

    if ((rxCount >= 0) && (rxCount < buffLen)) {

      rxCount++;

    }

  }

}

// ------------------------- Send BLE ------------------

void sendData(void) {

  byte titleInx;

  byte fldInx;

  int outsInx = 0;

  do {

    if (outputs[outsInx] >= 200) {

      titleInx = outputs[outsInx] - 200;

      String mesgOut(msgs[titleInx].keyCode);

      mesgOut += ":";

      mesgOut += msgs[titleInx].timestamp;

      mesgOut +=  "  ";

      dataCharacteristic.writeValue(mesgOut.c_str());

    }

    if ((outputs[outsInx] >= 100) && (outputs[outsInx] < 200)) {

      titleInx = outputs[outsInx] - 100;

      dataCharacteristic.writeValue(titles[titleInx].c_str());

    }

    if ((outputs[outsInx] >= 0) && (outputs[outsInx] < 100)) {

      fldInx = outputs[outsInx];

      titleInx = flds[fldInx].areaInx;

      String mesgOut(titles[titleInx]);

      titleInx = flds[fldInx].typeInx;

      if (titleInx != 255) {

        mesgOut += titles[titleInx];

      }

      mesgOut += String(flds[fldInx].fldData,flds[fldInx].len);

      if (flds[fldInx].len > 1) {

        mesgOut += ' ';

      }

      titleInx = flds[fldInx].unitsInx;

      if (titleInx != 255) {

        mesgOut += titles[titleInx];

      }

      dataCharacteristic.writeValue(mesgOut.c_str());

    }

    //Serial.print(titles[titleInx]);

    delay(BLEOffset);

    //Serial.println();

    if (outputs[outsInx] >= 0) {

      outsInx++;

    }

  } while (outputs[outsInx] > 0);

}