#include "BluetoothSerial.h"
BluetoothSerial ESP_BT; //Object for Bluetooth
//Wifi Manager
#include <WiFi.h>
#include <WebServer.h>
#include <AutoConnect.h>
WiFiClient wifiClient;
WebServer Server;
AutoConnect Portal;
AutoConnectConfig Config;
#ifndef AUTOCONNECT_UNITTIME
#define AUTOCONNECT_UNITTIME 3
#endif
//Oled declaration and settings
#include <Adafruit_GFX.h>
#include <gfxfont.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET -1 // Reset piwn # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
//MPU6050 Libraries and variables
#include <MPU6050_tockn.h>
MPU6050 mpu6050(Wire);
#include <Wire.h>
int Offset_Accel = 0;
int Offset_Rot = 0;
//MQTT declaratios and strings
#include <PubSubClient.h>
PubSubClient mqttClient(wifiClient);
const char* mqttServer = "141.94.204.149";
int mqttPort = 1883;
//UUID Generation and Values
#include <stdint.h>
#include <ESPRandom.h>
uint8_t uuid_array[16];
String uuid;
//Player Name
int once_stp = 1;
int once_stp_ask = 1;
String NickName = "Imferir_le_diplome";
String Vehicle_Color = "#800080";
int Vehicle_Type = 2;
//JsonLibrary
#include <ArduinoJson.h>
//Buttons Variables
int adc_key_in;
int key_no_repeat = 0;
static const unsigned char PROGMEM pi5a_glcd_bmp[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x03, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x7F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0xFF, 0xE6, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0xFF, 0xC2, 0x00, 0x00, 0x00, 0x03, 0xF0, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0xFE, 0xC0, 0x00, 0x00, 0x00, 0x03, 0xE0, 0x07, 0x03, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00,
0x03, 0xF0, 0xC0, 0x00, 0x00, 0x00, 0x07, 0xE0, 0x07, 0x03, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00,
0x03, 0xF8, 0xC0, 0x00, 0x00, 0x00, 0x07, 0xC0, 0x07, 0x03, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00,
0x00, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x0F, 0xC0, 0x00, 0x03, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x3F, 0xC6, 0x00, 0x00, 0x00, 0x0F, 0xC0, 0x00, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x07, 0xF6, 0x00, 0x00, 0x00, 0x0F, 0xC0, 0x00, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0xFE, 0x00, 0x00, 0x00, 0x0F, 0xC0, 0x00, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x0F, 0xC1, 0xFF, 0xE7, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0F, 0xC1, 0xFF, 0xC7, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0F, 0xC0, 0x3F, 0x07, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0F, 0xE0, 0x1F, 0x07, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x07, 0xE0, 0x1F, 0x07, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x70, 0x7F, 0x00, 0x00, 0x00, 0x07, 0xF0, 0x1F, 0x00, 0x03, 0xF8, 0x00, 0x00, 0x00, 0x00,
0x00, 0x70, 0xFF, 0x80, 0x00, 0x00, 0x03, 0xF8, 0x1F, 0x00, 0x01, 0xF8, 0x00, 0x00, 0x00, 0x00,
0x00, 0x71, 0xFF, 0xC0, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x01, 0xF8, 0x00, 0x00, 0x00, 0x00,
0x00, 0x71, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x01, 0xF8, 0x00, 0x00, 0x00, 0x00,
0x00, 0x71, 0xE1, 0xE0, 0x00, 0x00, 0x00, 0x3F, 0xFC, 0x00, 0x01, 0xF8, 0x00, 0x00, 0x00, 0x00,
0x00, 0x71, 0xE0, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x01, 0xF0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x71, 0xC0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x03, 0xF0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x71, 0xC0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xE7, 0xE0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x71, 0xC0, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x7F, 0xC0, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00,
0x00, 0x7F, 0xE1, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x7F, 0xE1, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0xFF, 0xFE, 0x0F, 0xFB, 0xFC, 0x0F, 0xF3, 0xFF, 0xF1, 0xFF, 0xE0, 0x7F, 0xDF, 0xFE, 0x00,
0x03, 0xFF, 0xFE, 0x0F, 0xF3, 0xFC, 0x0F, 0xF3, 0xFF, 0xF1, 0xFF, 0xF0, 0x7F, 0x9F, 0xFF, 0x00,
0x03, 0xFF, 0xFE, 0x03, 0xC0, 0xFC, 0x1F, 0xC0, 0xF0, 0x70, 0x78, 0xF8, 0x1E, 0x07, 0x8F, 0x80,
0x03, 0xFF, 0xFE, 0x03, 0xC0, 0xFE, 0x1F, 0xC0, 0xF0, 0x30, 0x78, 0x78, 0x1E, 0x07, 0x87, 0x80,
0x03, 0x00, 0x06, 0x03, 0xC0, 0xFE, 0x1F, 0xC0, 0xF0, 0x30, 0x78, 0x78, 0x1E, 0x07, 0x87, 0x80,
0x03, 0x00, 0x06, 0x03, 0xC0, 0xFE, 0x3B, 0xC0, 0xF1, 0xC0, 0x78, 0x78, 0x1E, 0x07, 0x87, 0x80,
0x00, 0x00, 0x00, 0x03, 0xC0, 0xFF, 0x3B, 0xC0, 0xF1, 0xC0, 0x78, 0xF8, 0x1E, 0x07, 0x8F, 0x80,
0x00, 0x30, 0x00, 0x03, 0xC0, 0xEF, 0x3B, 0xC0, 0xFF, 0xC0, 0x79, 0xF0, 0x1E, 0x07, 0x9F, 0x00,
0x00, 0xFE, 0x00, 0x03, 0xC0, 0xEF, 0x73, 0xC0, 0xFF, 0xC0, 0x7F, 0xE0, 0x1E, 0x07, 0xFE, 0x00,
0x01, 0xFF, 0x00, 0x03, 0xC0, 0xEF, 0xF3, 0xC0, 0xF1, 0xC0, 0x7F, 0xE0, 0x1E, 0x07, 0xFE, 0x00,
0x03, 0xFF, 0x80, 0x03, 0xC0, 0xE7, 0xF3, 0xC0, 0xF0, 0xC0, 0x7B, 0xF0, 0x1E, 0x07, 0xBF, 0x00,
0x03, 0xFF, 0x80, 0x03, 0xC0, 0xE7, 0xE3, 0xC0, 0xF0, 0x18, 0x79, 0xF0, 0x1E, 0x07, 0x9F, 0x00,
0x03, 0xC7, 0x80, 0x03, 0xC0, 0xE7, 0xE3, 0xC0, 0xF0, 0x18, 0x78, 0xF8, 0x1E, 0x07, 0x8F, 0x80,
0x03, 0x83, 0x80, 0x03, 0xC0, 0xE3, 0xC3, 0xC0, 0xF0, 0x38, 0x78, 0xFC, 0x1E, 0x07, 0x8F, 0xC0,
0x03, 0x01, 0x86, 0x0F, 0xF3, 0xF3, 0xCF, 0xF3, 0xFF, 0xF9, 0xFE, 0x7F, 0x7F, 0x9F, 0xE7, 0xF0,
0x03, 0x01, 0x86, 0x0F, 0xFB, 0xFB, 0xDF, 0xF3, 0xFF, 0xF9, 0xFE, 0x3F, 0xFF, 0xDF, 0xE3, 0xF8,
0x03, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
//MPU values structure to return from readMPU() function
struct MPU_reading
{
int accel;
int rot;
int accel_raw;
int rot_raw;
};
//KeyBoard buttons structure to return from CheckButtons() function
struct KBD_reading
{
bool btn1;
bool btn2;
bool btn3;
bool btn4;
bool btn5;
};
void setup_MPU() //initialize MPU with calculated offsets from previous calibration
{
Wire.begin();
mpu6050.begin();
mpu6050.setGyroOffsets(-3.11, -2.95, -0.86);
}
void setup_MQTT() //initialize the MQTT with both client address and client port
{
mqttClient.setServer(mqttServer, mqttPort);
}
void reconnect() //Reconnect to the MQTT if connection is lost
{
Serial.println("Connecting to MQTT Broker...");
while (!mqttClient.connected()) {
Serial.println("Reconnecting to MQTT Broker..");
String clientId = "SteeringWheel-";
clientId += String(random(0xffff), HEX);
if (mqttClient.connect(clientId.c_str())) {
Serial.println("Connected to broker.");
}
}
}
void setup_PORTAL() //setup the captive portal and wifi manager
{
Config.autoReset = false;
Config.autoReconnect = true;
Config.reconnectInterval = 1;
Portal.config(Config);
Portal.begin();
}
void generate_UUID()
{
ESPRandom::uuid4(uuid_array);
uuid = ESPRandom::uuidToString(uuid_array);
}
void setup_OLED()
{
display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS);
}
void setup() {
Serial.begin(115200); //debug only, uncomment if needed
pinMode(33, INPUT); //define GPIO33 as input
analogSetWidth(12); //define analog reading sampling
generate_UUID();
setup_OLED();
display.setRotation(0);
display.clearDisplay();
display.drawBitmap(0, 0, pi5a_glcd_bmp, 128, 64, 1);
display.display();
delay(1000);
setup_PORTAL();
setup_MPU();
}
void setup_Player(String uuid_str)
{
StaticJsonDocument<200> JSONencoderr;
JSONencoderr["nickname"] = NickName;
JSONencoderr["uuid"] = uuid_str;
JSONencoderr["color"] = Vehicle_Color;
JSONencoderr["vehicle_type"] = Vehicle_Type;
char JSONmessageBufferTwice[200];
serializeJson(JSONencoderr, JSONmessageBufferTwice);
mqttClient.publish("/subscribe", JSONmessageBufferTwice );
}
void loop() {
if (WiFi.status() == WL_CONNECTED) {
if(once_stp_ask)
{
once_stp_ask=0;
display.setRotation(3);
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0, 17);
for (int i = 0; i < 4; i++)
{
display.println(" ");
}
display.println("Connect to Bluetooth via Client");
display.display();
ESP_BT.begin("Steering_Wheel_G5");
while (!ESP_BT.available())
{
delay(1);
}
String message;
while (ESP_BT.available())
{
char inCome = ESP_BT.read();
message += String(inCome);
}
StaticJsonDocument<200> doc;
deserializeJson(doc, message);
const char* mserver = doc["broker_address"];
mqttServer = mserver;
String vcolor = doc["vehicle_color"];
Vehicle_Color = vcolor;
int vtype = doc["vehicle_type"];
Vehicle_Type = vtype;
String nick = doc["nickname"];
NickName = nick;
//ESP_BT.println(nick);
//ESP_BT.println(vtype);
//ESP_BT.println(vcolor);
setup_MQTT();
//setup player with bluetooth for MQTT IP, car color, car type and NickName
}
if (!mqttClient.connected())
{
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0, 17);
for (int i = 0; i < 5; i++)
{
display.println(" ");
}
display.println("Connecting");
display.println("to MQTT...");
display.display();
delay(10);
reconnect();
}
else
{
if(once_stp)
{
once_stp=0;
setup_Player(uuid);
}
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0, 17);
for (int i = 0; i < 4; i++)
{
display.println(" ");
}
display.println("Connected!");
display.println(" ");
display.println("Enjoy your game");
display.display();
reconnect();
MPU_reading gyro_meter = readMPU();
KBD_reading kbd_input = Check_Buttons();
if (kbd_input.btn5)
Make_Zero(gyro_meter.accel_raw, gyro_meter.rot_raw);
StaticJsonDocument<250> JSONencoder;
JSONencoder["acceleration"] = -gyro_meter.accel;
JSONencoder["uuid"] = uuid;
JSONencoder["orientation"] = gyro_meter.rot;
JSONencoder["button_banana"] = kbd_input.btn4;
JSONencoder["button_missile"] = kbd_input.btn1;
JSONencoder["button_bomb"] = kbd_input.btn3;
JSONencoder["button_supp"] = kbd_input.btn2;
char JSONmessageBuffer[250];
serializeJson(JSONencoder, JSONmessageBuffer);
mqttClient.publish("/controller", JSONmessageBuffer );
}
}
Portal.handleClient();
}
MPU_reading readMPU() //update the values from the MPU then process them before they're stored in a struct that is returned from the function
{
struct MPU_reading values;
mpu6050.update();
values.accel = map(mpu6050.getAngleY(), 120 , -120 , 100, -100) - Offset_Accel;
if (values.accel > 100)
values.accel = 100;
else if (values.accel < -100)
values.accel = -100;
values.accel_raw = map(mpu6050.getAngleY(), 120 , -120 , 100, -100);
values.rot = map(mpu6050.getAngleZ(), 120 , -120 , 100, -100) - Offset_Rot;
if (values.rot > 100)
values.rot = 100;
else if (values.rot < -100)
values.rot = -100;
values.rot_raw = map(mpu6050.getAngleZ(), 120 , -120 , 100, -100);
return values;
}
KBD_reading Check_Buttons() //read the analog GPIO before processing it and converting it into a struct with true or false depending on wich button is pressed
{
struct KBD_reading buttons;
adc_key_in = analogRead(33);
if (adc_key_in < 4095 && key_no_repeat == 0)
{
if (adc_key_in > 3920 && adc_key_in < 3960)
{
//Serial.println("S5");
buttons.btn5 = true;
key_no_repeat = 1;
}
else if (adc_key_in > 3530 && adc_key_in < 3560)
{
//Serial.println("S4");
buttons.btn4 = true;
key_no_repeat = 1;
}
else if (adc_key_in > 3330 && adc_key_in < 3360)
{
//Serial.println("S3");
buttons.btn3 = true;
key_no_repeat = 1;
}
else if (adc_key_in > 3205 && adc_key_in < 3230)
{
//Serial.println("S2");
buttons.btn2 = true;
key_no_repeat = 1;
}
else if (adc_key_in > 9120 && adc_key_in < 9160)
{
//Serial.println("S1");
buttons.btn1 = true;
key_no_repeat = 1;
}
}
else
{
key_no_repeat = 0;
buttons.btn1 = 0;
buttons.btn2 = 0;
buttons.btn3 = 0;
buttons.btn4 = 0;
buttons.btn5 = 0;
}
return buttons;
}
void Make_Zero(int tooffset, int tooffset2) //allow the user to define it's own zero position, for a comfortable play time
{
MPU_reading gyro_meter = readMPU();
Offset_Accel = tooffset; //-map(gyro_meter.accel_raw,120 ,-120 , -100, 100);
Offset_Rot = tooffset2; //-map(gyro_meter.rot_raw,120 ,-120 , -100, 100);
}